C Manuseamento # Exceção continuar em caso de erro
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;
}
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.