web-dev-qa-db-ja.com

最速の検索を提供する.NETコレクション

20,000個のルックアップリストに対してチェックする必要がある60k個のアイテムがあります。例外的に高速なContains()メソッドを提供するコレクションオブジェクト(ListHashTableなど)はありますか?または、自分で書く必要がありますか?つまり、デフォルトのContains()メソッドは、各アイテムをスキャンするだけであるか、より良い検索アルゴリズムを使用します。

foreach (Record item in LargeCollection)
{
    if (LookupCollection.Contains(item.Key))
    {
       // Do something
    }
}

。ルックアップリストは既にソートされています。

133
Brig Lamoreaux

最も一般的なケースでは、 System.Collections.Generic.HashSet をデフォルトの「含む」主力データ構造として検討してください。Containsの評価には一定の時間がかかるためです。

「最速の検索可能なコレクションとは」に対する実際の答えは、特定のデータサイズ、順序付け、ハッシュコスト、および検索頻度によって異なります。

133
Jimmy

注文する必要がない場合は、HashSet<Record>を試してください(.Net 3.5の新機能)

その場合は、List<Record>を使用してBinarySearchを呼び出します。

69
SLaks

List.BinarySearch(item)を検討しましたか?

あなたの大規模なコレクションは既にソートされているので、これは絶好の機会のように思えますか?ハッシュは間違いなく最速ですが、これは独自の問題を引き起こし、ストレージのためにより多くのオーバーヘッドを必要とします。

22
Mark

このブログ を読む必要があります。シングルスレッドとマルチスレッドの両方の手法を使用して、さまざまな種類のコレクションとメソッドをそれぞれテストしました。

結果によると、ListとSortedListでのBinarySearchは、「値」として何かを検索する際に首をつねに常に実行しているトップパフォーマーでした。

「キー」を許可するコレクションを使用すると、Dictionary、ConcurrentDictionary、Hashset、およびHashTablesが全体的に最高のパフォーマンスを発揮しました。

9
user3810900

リストxとyの両方をソート順に保持します。

X = yの場合はアクションを実行し、x <yの場合はxを進め、y <xの場合はいずれかのリストが空になるまでyを進めます。

この交差の実行時間は、min(サイズ(x)、​​サイズ(y))に比例します

しない .Contains()ループを実行します。これはx * yに比例しますが、これははるかに悪いです。

4
clemahieu

アイテムを並べ替えることができる場合は、ハッシュテーブルまたはBツリーへのキールックアップを実行して、これを行うはるかに高速な方法があります。ただし、アイテムがソートできない場合は、とにかくBツリーに入れることはできません。

とにかく、両方のリストをソート可能な場合は、ルックアップリストを順番に調べるだけです。

Walk lookup list
   While items in check list <= lookup list item
     if check list item = lookup list item do something
   Move to next lookup list item
3
Rich Schuler

.Net 3.5を使用している場合、以下を使用してよりクリーンなコードを作成できます。

foreach (Record item in LookupCollection.Intersect(LargeCollection))
{
  //dostuff
}

私はここに.Net 3.5を持っていないので、これはテストされていません。拡張メソッドに依存します。 LookupCollection.Intersect(LargeCollection)はおそらくLargeCollection.Intersect(LookupCollection)と同じではありません...後者はおそらくずっと遅いです。

これは、LookupCollectionがHashSetであることを前提としています

3
Brian

パフォーマンスの最後のすべてのビットをきしむことを心配していない場合は、HashSetまたはバイナリ検索を使用することをお勧めします。データセットが十分に大きくないため、99%の確率でこれが問題になります。

しかし、これを行うのが数千回のうちの1回であり、パフォーマンスが重要な場合(そしてHashSet/binary searchを使用して受け入れられないことが証明されている場合)、あなたが行ったように比較を行うソート済みリストを歩く独自のアルゴリズムを確かに書くことができます。各リストは多くても1回しか歩かず、病理学的なケースでは悪くはありません(このルートに進むと、文字列またはその他の非整数値であると仮定した場合の比較が実際の費用であり、その最適化が次のステップになります)。

2
Robert Horvick