2016-08-17 4 views
2

私はExcelデータのグリッドを解析し、オブジェクトモデルを構築しました。 32の列と100,000の行があります。私は重複したデータを持つ行をチェックして報告するように求められてきました。私の実装では、私は次のことをやっています:C#コレクションのパフォーマンス:この目的のために、Hashset <string>とDictionary <string、IList <int>>が最速のコレクションですか?

  1. 私は行IDと連結セルの内容を持つタプルの配列を構築しています。
  2. 結果セットをループし、HashSetを使用して、連結された値をHashSetに挿入しようとします。
  3. HashSet.Add()がパスすると、辞書>結果セットに新しいエントリが作成されます。
  4. HashSet.Addは()の結果は、残りはプロセスに822sを取っている間、ステップ1は、0.09s取る

設定>私は私の辞書の既存のエントリにその行番号を追加し失敗した場合

  • :/は誰にもでき私はコレクションやアルゴリズムのより適切な選択肢を使ってこの時間を短縮することができます。

    コードは以下の通りです:このような状況の問題で

    var results = new Dictionary<string, IList<int>>(numberOfRows); 
    var hashSet = new HashSet<string>(); 
    var duplicateErrors = new List<string>(); 
    
    for (var row = firstRow; row <= lastRow; row++) 
    { 
        var row1 = row; 
        taskArray[count++] = 
        Task<Tuple<int, string>>.Factory.StartNew(() => GetCompleteRowData(row1, tableRawDataHolders)); 
    } 
    
    foreach (var task in taskArray) 
    { 
        if (hashSet.Add(task.Result.Item2)) 
        { 
         results.Add(task.Result.Item2, new List<int>() { task.Result.Item1 }); 
        } 
        else 
        { 
         results[task.Result.Item2].Add(task.Result.Item1); 
        } 
    } 
    

    public Tuple<int, string> GetCompleteRowData(int row, IEnumerable<ITableRawDataHolder> tableRawDataHolders) 
        { 
         return new Tuple<int, string>(row, string.Join("", 
          tableRawDataHolders.Where(c => c.Row == row).Select(c => c.Value).ToArray())); 
        } 
    

    public class TableRawDataHolder : ITableRawDataHolder 
    { 
        public int Row { get; } 
        public int Column { get; } 
        public string Value { get; } 
    
        public TableRawDataHolder(int row, int column, string value) 
        { 
         Row = row; 
         Column = column; 
         Value = value; 
        } 
    } 
    
  • +0

    それは実際に 'Dictionary'性能対Hashset''については何の関係もありません。タイトルは同じように見えますが、質問を慎重に読んでください。 OPは、200000行の間で重複を探すことを求めている。 –

    +1

    * "ステップ1には0.09秒かかりますが、残りは822秒で処理されます:/" *。それは実際にはありません。非同期でタスクを開始するには、0.09秒かかります。しかし、 'task.Result'にアクセスしようとすると、スレッドをブロックします。 –

    +0

    @YeldarKurmangaliyevがいくつかの良い議論をして以来、私は再開することを表明しました。それでも、[この投稿](http://stackoverflow.com/q/2728500/993547)が便利です。 –

    答えて

    2

    辞書やHashSetの性能ではありません。

    オーバーヘッドは、GetCompleteRowDataでデータを読み取り、タスクを処理する方法に由来します。

    • 次のレコードを変換する必要があるたびにフルコレクションを列挙しているようです。
    • 次のすべてのレコードに対して、それ自身で小さなオーバーヘッドを追加するタスクを作成します。タスクが終了するまで、task.Resultを使用するときだけ待機します。
    • また、ITableRawDataHolderがどのくらい速くデータを返すかは明確ではありません。

    純粋なハッシュセット/ディクショナリのパフォーマンスを実証するために、私は既に準備されたタプルの配列を反復するテストを作成しました。このコードは私のマシン(i7 quad core)上でわずか32msしかかかりません。ここで

    const Int32 numberOfRows = 200000; 
    var inputData = GetInputData(numberOfRows); 
    var results = new Dictionary<string, IList<int>>(numberOfRows); 
    var hashSet = new HashSet<string>(); 
    
    var sw = Stopwatch.StartNew(); 
    foreach (var dataItem in inputData) 
    { 
        if (hashSet.Add(dataItem.Item2)) 
        { 
         results.Add(dataItem.Item2, new List<int>() {dataItem.Item1}); 
        } 
        else 
        { 
         results[dataItem.Item2].Add(dataItem.Item1); 
        } 
    } 
    Console.WriteLine(sw.ElapsedMilliseconds); 
    

    は、私がテストデータを生成する方法である(それはいくつかの実際の重複を含ん)

    private static List<Tuple<int, String>> GetInputData (int numberOfRows) 
    { 
        var result = new List<Tuple<int, String>>(numberOfRows); 
        var rnd = new Random(); 
        for (var i = 0; i < numberOfRows; i++) 
        { 
         // Once in 100 records we'll have not unique value 
         if (result.Count > 0 && rnd.Next(100)%1 == 0) 
         { 
          result.Add(new Tuple<int, string>(i, result[rnd.Next(result.Count)].Item2)); 
         } 
         else 
          result.Add(new Tuple<int, string>(i, Guid.NewGuid().ToString())); 
        } 
        return result; 
    } 
    
    +0

    ありがとうございました!私の入力を変更してIDIctionary >でキーを行番号としてラップすることを考えました。私はもはやすべての行のすべてのデータをLINQで照会する必要はなく、処理時間を822秒から22秒に短縮しました。本当にありがとうございます。 –

    +0

    私は助けてうれしいです。 22秒はまだかなり大きく見えますが。あなたはExcelからのデータを持っていると言いましたが、最適化できる方法でそのデータをExcelから読み取っている可能性があります。たとえば、あるセルでセルを読み取るのではなく、アレイ内で全セル範囲を一度に読み取るほうが速い場合があります。 – dlxeon

    +0

    全シート、32列×100000行です。さらなるボトルネックのためにコードを取得するコードを見ていきます。 –

    関連する問題