2012-01-24 8 views
6

Iは整数であり、(数字で開始することができる)、英数字の文字列となっている第二である第一その値の対からなるデータ構造を有する:どのC#データ構造によって、部分文字列に対して最も効率的に文字列のペアを検索できますか?

+--------+-----------------+ 
| Number | Name   | 
+--------+-----------------+ 
| 15  | APPLES   | 
| 16  | APPLE COMPUTER | 
| 17  | ORANGE   | 
| 21  | TWENTY-1  | 
| 291 | 156TH ELEMENT | 
+--------+-----------------+ 

これらのテーブルだろう100,000行までを構成します。

私は、数字(文字列のように)または文字列の一部のいずれかをユーザーが検索できるルックアップ機能を提供したいと考えています。理想的には、ユーザのタイプに応じてルックアップが「ライブ」になります。各キーストロークの後(または、わずかに遅れて〜250-500ms後)、最も可能性の高い候補を見つけるために新しい検索が行われる。そのため、例えば、理想的(291 156TH ELEMENT

  • AP15 APPLES16 APPLE COMPUTER
  • を返し、15 APPLESに検索を絞り込むます15 APPLES16 APPLE COMPUTER17 ORANGE、および291 156TH ELEMENT
  • 15 を返します

    • 1で検索、必須ではありません)ELEM291 156TH ELEMENTを返します。

    Iは、最終的int sはstring sと比較されているから2つのDictionary<string, string> Sを使用して考えていた - 文字列の一部ずつ意志の整数部分によってインデックスおよびその他。

    しかし、実際に部分文字列で検索するとハッシュ関数を使用すべきではありません。必要と思われるメモリを2倍使用するのは無駄です。

    最終的には、サブストリングのために2つの大きなリストを同時にテキスト検索することはうまくいくのですか?

    これが失敗すると、SortedDictionaryはどうですか?パフォーマンスは向上しますが、ハッシュの問題は解決されません。

    オンザフライで正規表現を作成することについて考えましたが、それはひどく実行すると思います。

    私はLINQをまだ見ていないので、私はC#(Javaの世界から来たもの)が新です。それは答えですか?

    EDIT 18:21 EST:潜在的な解決方法に影響する場合、「名前」フィールドの文字列は12-15文字より長くなりません。

  • +0

    Iは(http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm)[クヌース - モリス - プラット法]のわずかに修飾された実装と思います便利である。 – ChaosPandion

    +0

    あなたが「効率的に」と言うとき、あなたは「素早く」または最小のメモリを意味しますか?一般に、これらのシナリオでは、メモリの速度を交換したり、2つのバランスをとることができます。かなり静的な100kの文字列もあります。つまり、回転率はほとんどなく、繰り返し検索されていますか? – EBarr

    +0

    @エバー:メモリは大きな問題ではありませんが、私は無駄になりたくありません。ここでスピードが重要です。 – Tenner

    答えて

    3

    私はTrieデータ構造の使用を検討したいと思います。

    これを達成する方法は?リーフはあなたの「行」を表しますが、「行」の各メモリインスタンスには「2つのパス」があります(数字用と名前用の2つのパス)。

    次に、あなたの条件を犠牲にすることができます

    (ideally, but not required) ELEM will return 291 156TH ELEMENT. 
    

    またはあなたの行インスタンスにも、複数のパスを提供します。

    +0

    ;私は確かにこれを実装し、どのようにうまくいくかを見ていきます。私はこの事実を元のポストには含めなかったが、プログラムの開始時にはおそらく最初のツリー作成を行うことができる。もしそれが少し余分な時間を要するなら、それは確かに世界の終わりではありません。ありがとう! – Tenner

    +0

    ここに点があります。パンチに私を打ちなさい;-) – EBarr

    +0

    「メモリ使用量に関して最適なもの」よりも「邪悪な」ソリューションです。それは、あなたがそれを実装するときに子供のように泣くようなものです:) Philによって言及されているように、Lucene.Netは良い解決策ですが、実際にはあなたの特定のユースケースに依存します。そのような文字列の100k ...おそらく〜1メガバイトです。あなたがそれらをメモリ上で利用できるようにしているのであれば、それほど実際にはありませんが、要求に応じて何度もデータベースからそれらを引き出し、最初にトライを構築する必要があります。 – doblak

    6

    可能であれば、すべての100,000エントリをメモリに読み込まないようにします。私はデータベースまたはLucene.Netのいずれかを使用して値を索引付けします。次に、適切なクエリ構文を使用して、結果を効率的に検索します。

    +2

    それはすべての楽しみを取りますが.... – ChaosPandion

    +0

    私が上で概説したものは、製品のごく一部であり、私は本当に軽量の解決策を可能にしたいと思っています。それがうまくいくものがあれば私は確かにLucene.netをメモリに入れておきます。ありがとう!興味深い; – Tenner

    1

    "a"、 "ap"、 "app"、 "appl"、 "apple"などの単語のすべての部分を保存しない限り、単語の先頭を検索しているので、キーベースのコレクションは機能しません"

    私の提案は、System.Collections.Generic.List<T>とバイナリ検索を併用することです。あなた自身もIComparer<T>を提供しなければならないでしょう。これはまた単語の始まりを見つけます。 2つのデータ構造を使用します。

    List<KeyValuePair<string,int>>は、単一の単語または数字をキーとして、数値を値として保持します。

    名前全体を保持するDictionary<int,string>

    あなたは次のように進行する:

    1. 単一の単語にあなたの文章(全体の名前)を分割します。

    2. 単語をキーとして、数字をKeyValuePairの値としてリストに追加します。

    3. 数字をKeyValuePairのキーと値としてリストに追加します。

    4. リストがいっぱいになると、バイナリ検索を可能にするためにリストをソートします。

    単語の先頭を検索:

    1. 検索リストであなたのIComparer<T>と一緒にBinarySearchを使用します。

    2. 検索から得られるインデックスが最初に適用されるインデックスでない可能性があるので、最初に一致するエントリが見つかるまでリストに戻ってください。

    3. リストに値として格納されている番号を使用して、この番号をキーとして使用して辞書内の名​​前全体を検索します。

    関連する問題