2

テキストファイル(CSV形式)を1行ずつ読み取り、データをHashTableに配置する基本的なC#コンソールアプリケーションがあります。行の最初のCSV項目はキー(id num)であり、行の残りの部分は値です。ただし、インポートファイルに、あるべきではない重複キーがいくつかあることがわかりました。ファイルをインポートしようとすると、HashTableに重複するキーを含めることができないため、アプリケーションでエラーが発生します。ただし、プログラムでこのエラーを処理できるようにしたいと思います。重複するキーに遭遇した場合、そのキーを配列リストに入れ、残りのデータをハッシュテーブルにインポートし続けたいと思います。C#でこれを行うにはどうすればよいですか?

これが私のコードです:


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

たとえば、CSV値が4つを超える場合は、文字列の連結が遅い関数であるため、StringBuilderも使用するように値変数を設定する価値があります。

于 2008-09-25T17:42:13.330 に答える
1

うーん、170万行?私はそのような負荷のためにこれを提供することを躊躇します.

LINQ を使用してこれを行う 1 つの方法を次に示します。

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 万行を読み込んでいますが、プログラムが 2 つのファイルを読み込んで比較し、いくつかのファイルを書き出すのに合計で約 7 分かかります。ファイルの比較と書き出しに約 2 秒しかかかりません。

于 2008-09-25T17:05:30.563 に答える