2

我有一个基本的 C# 控制台应用程序,它逐行读取文本文件(CSV 格式)并将数据放入 HashTable。行中的第一个 CSV 项是键(id num),行的其余部分是值。但是我发现我的导入文件有一些不应该有的重复键。当我尝试导入文件时,应用程序出错,因为哈希表中不能有重复的键。我希望我的程序能够处理这个错误。当我遇到重复键时,我想将该键放入 arraylist 并继续将其余数据导入哈希表。我如何在 C# 中做到这一点

这是我的代码:


私有静态哈希表导入文件(哈希表 myHashtable,字符串 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;
    }
4

7 回答 7

10
if (myHashtable.ContainsKey(key))
    duplicates.Add(key);
else
    myHashtable.Add(key, value);
于 2008-09-25T16:20:10.487 回答
3

更好的解决方案是调用 ContainsKey 来检查密钥是否存在,然后再将其添加到哈希表中。对这种错误抛出异常会影响性能,并且不会改善程序流程。

于 2008-09-25T16:14:07.270 回答
3

ContainsKey 对每个项目都有恒定的 O(1) 开销,而捕获异常只会对重复项目造成性能影响。

在大多数情况下,我会说检查密钥,但在这种情况下,最好捕获异常。

于 2008-09-25T16:26:37.663 回答
1

这是一个解决方案,可以避免二级列表中的多次命中,所有插入的开销都很小:

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

您可以将字典包装在隐藏它的类型中,或者将其放在字典上的方法甚至扩展方法中。

于 2008-09-25T16:42:29.403 回答
1

如果您有超过 4 个(例如)CSV 值,则可能值得将变量设置为使用 StringBuilder,因为字符串连接是一个慢速函数。

于 2008-09-25T17:42:13.330 回答
1

嗯,170 万行?我犹豫要不要为这种负载提供这个。

这是使用 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);
  } 
}
于 2008-09-25T17:51:27.660 回答
0

谢谢你们。我最终使用了 ContainsKey() 方法。它可能需要多花 30 秒,这对我的目的来说很好。我正在加载大约 170 万行,该程序总共需要大约 7 分钟来加载两个文件、比较它们并写出一些文件。进行比较和写出文件只需要大约 2 秒。

于 2008-09-25T17:05:30.563 回答