Pregunta

Tengo una aplicación de consola C # básica que lee un archivo de texto (formato CSV) línea por línea y coloca los datos en una tabla hash. El primer elemento CSV en la línea es la clave (número de identificación) y el resto de la línea es el valor. Sin embargo, he descubierto que mi archivo de importación tiene algunas claves duplicadas que no debería tener. Cuando intento importar el archivo, la aplicación falla porque no puedes tener claves duplicadas en una tabla hash. Sin embargo, quiero que mi programa pueda manejar este error. Cuando me encuentro con una clave duplicada, me gustaría poner esa clave en un arraylist y seguir importando el resto de los datos en la tabla hash. ¿Cómo puedo hacer esto en C #

Aquí está mi código:


Hashtable importFile privado estático (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;
    }
¿Fue útil?

Solución

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

Otros consejos

Una mejor solución es llamar a ContainsKey para verificar si existe la clave antes de agregarla a la tabla hash. La excepción de este tipo de error es un golpe de rendimiento y no mejora el flujo del programa.

ContainsKey tiene una sobrecarga constante de O (1) para cada elemento, mientras que la captura de una Excepción incurre en un impacto de rendimiento en SOLO los elementos duplicados.

En la mayoría de las situaciones, diría que buscar la clave, pero en este caso, es mejor detectar la excepción.

Aquí hay una solución que evita múltiples visitas en la lista secundaria con una pequeña sobrecarga en todas las inserciones:

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);

Puede ajustar el diccionario en un tipo que lo oculte o ponerlo en un método o incluso en un método de extensión en el diccionario.

Si tiene más de 4 (por ejemplo) valores CSV, podría valer la pena configurar la variable valor para utilizar también un StringBuilder, ya que la concatenación de cadenas es una función lenta.

Hmm, 1.7 millones de líneas? Dudo en ofrecer esto para ese tipo de carga.

Aquí hay una forma de hacerlo 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);
  } 
}

Gracias a todos. Terminé usando el método ContainsKey (). Tarda tal vez 30 segundos más, lo cual está bien para mis propósitos. Estoy cargando alrededor de 1.7 millones de líneas y el programa toma aproximadamente 7 minutos en total para cargar dos archivos, compararlos y escribir algunos archivos. Solo toma aproximadamente 2 segundos hacer la comparación y escribir los archivos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top