Pergunta

Eu tenho um C # aplicação básica do console que lê um arquivo de texto (formato CSV) linha por linha e coloca os dados em um HashTable. O primeiro item CSV na linha é a chave (id numérico) eo resto da linha é o valor. No entanto, eu descobri que o meu ficheiro de importação tem algumas chaves duplicadas que não deveria ter. Quando eu tento importar o arquivo os erros de aplicação, porque você não pode ter chaves duplicadas em um HashTable. Eu quero o meu programa para ser capaz de lidar com esse erro embora. Quando eu me deparo com uma cópia da chave que eu gostaria de colocar a chave em um ArrayList e continuar importando o resto dos dados no hashtable. Como posso fazer isso em C #

Aqui está o meu código:


private static Hashtable ImportFile (Hashtable myHashtable, String myFileName) {

        StreamReader sr = new StreamReader(myFileName);
        CSVReader csvReader = new CSVReader();
        ArrayList tempArray = new ArrayList();
        int count = 0;

        while (!sr.EndOfStream)
        {
            String temp = sr.ReadLine();
            if (temp.StartsWith(" "))
            {
                ServMissing.Add(temp);
            }
            else
            {
                tempArray = csvReader.CSVParser(temp);
                Boolean first = true;
                String key = "";
                String value = "";

                foreach (String x in tempArray)
                {
                    if (first)
                    {
                        key = x;
                        first = false;
                    }
                    else
                    {
                        value += x + ",";
                    }
                }
                myHashtable.Add(key, value);
            }
            count++;
        }

        Console.WriteLine("Import Count: " + count);
        return myHashtable;
    }
Foi útil?

Solução

if (myHashtable.ContainsKey(key))
    duplicates.Add(key);
else
    myHashtable.Add(key, value);

Outras dicas

Uma solução melhor é chamar ContainsKey para verificar se a exist chave antes de adicionar à tabela de hash em vez. Lançando exceção sobre este tipo de erro é um acerto de desempenho e não melhora o fluxo do programa.

ContainsKey tem uma constante O (1) sobrecarga para cada item, enquanto captura uma exceção incorre em um acerto de desempenho em apenas os itens duplicados.

Na maioria das situações, eu diria verificação para a chave, mas neste caso, o seu melhor para capturar a exceção.

Aqui está uma solução que evita vários hits na lista secundária com uma pequena sobrecarga para todas as inserções:

Dictionary<T, List<K>> dict = new Dictionary<T, List<K>>();

//Insert item
if (!dict.ContainsKey(key))
   dict[key] = new List<string>();
dict[key].Add(value);

Você pode envolver o dicionário em um tipo que esconde este ou colocá-lo em um método método ou até mesmo extensão no dicionário.

Se você tem mais de 4 (por exemplo) os valores CSV, pode valer a pena definir o valor variável para usar um StringBuilder bem desde a concatenação é uma função lenta.

Hmm, 1,7 milhões de linhas? Hesito em oferecer este para esse tipo de carga.

Aqui está uma maneira de fazer isso usando LINQ.

CSVReader csvReader = new CSVReader();
List<string> source = new List<string>();
using(StreamReader sr = new StreamReader(myFileName))
{
  while (!sr.EndOfStream)
  {
    source.Add(sr.ReadLine());
  }
}
List<string> ServMissing =
  source
  .Where(s => s.StartsWith(" ")
  .ToList();
//--------------------------------------------------
List<IGrouping<string, string>> groupedSource = 
(
  from s in source
  where !s.StartsWith(" ")
  let parsed = csvReader.CSVParser(s)
  where parsed.Any()
  let first = parsed.First()
  let rest = String.Join( "," , parsed.Skip(1).ToArray())
  select new {first, rest}
)
.GroupBy(x => x.first, x => x.rest)   //GroupBy(keySelector, elementSelector)
.ToList()
//--------------------------------------------------
List<string> myExtras = new List<string>();
foreach(IGrouping<string, string> g in groupedSource)
{
  myHashTable.Add(g.Key, g.First());
  if (g.Skip(1).Any())
  {
    myExtras.Add(g.Key);
  } 
}

Obrigado a todos. Acabei usando o método ContainsKey (). Demora talvez 30 segundos mais longo, o que é bom para os meus propósitos. Estou carregamento cerca de 1,7 milhões de linhas eo programa leva cerca de 7 minutos no total para carregar dois arquivos, compará-los, e escrever alguns arquivos. Leva apenas cerca de 2 segundos para fazer a comparar e escrever os arquivos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top