2011-10-19 9 views
12

私は次のように使用しています私のコードでDictionary<string, List<int>>を持っている:ディクショナリの文字列キーで文字列の部分一致を行うことはできますか?

Key   Values 
2011-07-15 1, 2, 3 
2011-07-20 4, 5, 6 
2010-02-11 7, 8, 9 

私のコードは、キー内の特定の部分文字列に一致するすべての値を照会できるようにする必要があります。たとえば、サブストリング2011-07がある場合は、値{1, 2, 3, 4, 5, 6}が返されます。サブストリング11は、すべてのIDを1-9から戻す必要があります。

これを達成するための簡潔な方法をお勧めしますか?または、この情報を取得するためのより良いデータ構造を提供しますか?

+0

以下の答えの多様性は、人々が "部分文字列"が意味することについて異なることを想定していることを示していると思います。私はあなたのコメント11から、必ずしも接頭辞、接尾辞、[年|月|日]だけではなく、正規表現ではない本当に一般的な部分文字列を意味すると仮定します。 –

+1

@J Trana - あなたは正しいです、私は本当に一般的な部分文字列を意味しました。 – LeopardSkinPillBoxHat

+0

@LeopardSkinPillBoxHat、あなたが一緒に行った最終的な解決策を投稿してください。 – EndlessSpace

答えて

8

私は、拡張メソッドを行うだろう部分一致となる。

Btw、私はあなたが単一のラムダ式でこれを変形できると確信していますが、コンセプトは同じです。

:この例では、このメソッドは2つの値リストを返しますが、リストをマージするために変更できます。 2が

public static IEnumerable<T> PartialMatch<T>(
    this Dictionary<string, IEnumerable<T>> dictionary, 
    string partialKey) 
{ 
    // This, or use a RegEx or whatever. 
    IEnumerable<string> fullMatchingKeys = 
     dictionary.Keys.Where(currentKey => currentKey.Contains(partialKey)); 

    List<T> returnedValues = new List<T>(); 

    foreach (string currentKey in fullMatchingKeys) 
    { 
     returnedValues.AddRange(dictionary[currentKey]); 
    } 

    return returnedValues; 
} 

編集:ここではあなたができる拡張メソッドで考えてみれば、あなたもそれをより汎用的にすることができます。次の拡張メソッドを使用すると、それは限り、あなたは、あなたが「部分一致」によって何を意味するかをチェックcomparerを提供して、任意の辞書に動作します:

public static IEnumerable<TValue> PartialMatch<TKey, TValue>(
    this Dictionary<TKey, IEnumerable<TValue>> dictionary, 
    TKey partialKey, 
    Func<TKey, TKey, bool> comparer) 
{ 
    // This, or use a RegEx or whatever. 
    IEnumerable<TKey> fullMatchingKeys = 
     dictionary.Keys.Where(currentKey => comparer(partialKey, currentKey)); 

    List<TValue> returnedValues = new List<TValue>(); 

    foreach (TKey currentKey in fullMatchingKeys) 
    { 
     returnedValues.AddRange(dictionary[currentKey]); 
    } 

    return returnedValues; 
} 
+0

これは良いアプローチです。 – DarthVader

+0

2番目の編集では、適切な比較メソッドを渡すと、辞書のキータイプがintになり、43が部分的に343756に一致すると言えます。 – Tipx

1

簡潔な方法は、マルチバリューマップを使用することです。例えば

Dictionary<string, Dictionary<string, List<int>> 

は、なぜあなたは内側の辞書のキーと値として1,2,3のための鍵と15と2011から07を格納していけません。

map ["2011-07"] ["15"] = {1,2,3};

場合は、ちょうど2011-07をしたい場合は、他の辞書内のすべてをトラバーサルで取得することができます。

map["2011-07"]が// uは

を1,2,3,4,5,6、あなたが特定の日に行きたい場合は、2011-07-15戻ってくる、これが唯一の1,2,3

Uを返します
foreach(var element in map["2011-07"]){ 

    var values = element.values; // and you can append them to a list. 

} 

年/月/日が必要な場合は、マルチレベル辞書が必要です。またはツリーを使用することもできます。

+0

例を提供したりポイントしたりできますか? – LeopardSkinPillBoxHat

+0

あなたの提案は私の2番目の例を助けません - 私は部分文字列を提供できるようにしたい - 年/月/日にきれいに壊れる必要はありません。 – LeopardSkinPillBoxHat

+0

編集を参照してください。ごめんなさい。 – DarthVader

2

ディクショナリが内部的にハッシュを使用する場合、類似した文字列が異なるハッシュを生成するため、あなたは不運です。私はちょうどCの週末、面接テスト/宿題のこの要件へのソリューションを実装しました。私は、高価な挿入物ではなく、高速検索(バイナリ検索を使用)の下にある構造体としてソートされた配列を使用しました。接頭辞で始まるキーを持つすべてのエントリを見つけるには、1番目を見つけて次に進む、次に進む...一般的な部分文字列、つまり接頭辞だけでなく、私の解決策は機能しません。現時点では、私は "一般的な部分文字列"検索のために何を提案するか分からない。

2

3つの辞書があります。年月日。

3つの辞書に項目を追加するときは、項目を複製しないことに注意してください。

2つのキーを使用して項目を取り出すときに、LINQ拡張メソッドIntersect()を使用して、両方のキーに一致する項目を取得できます(2つの結果セットで交差を使用)。

このようにしても、実行するコードが最も速くなるわけではありません。辞書に値を追加する「コスト」は変化しない

public static class DictionaryExt 
{ 
    public static IEnumerable<T> PartialMatch<T>(this Dictionary<string, T> dictionary, string partialKey) 
    { 
     // This, or use a RegEx or whatever. 
     IEnumerable<string> fullMatchingKeys = 
      dictionary.Keys.Where(currentKey => currentKey.Contains(partialKey)); 

     List<T> returnedValues = new List<T>(); 

     foreach (string currentKey in fullMatchingKeys) 
     { 
      returnedValues.Add(dictionary[currentKey]); 
     } 

     return returnedValues; 
    } 
} 

が、検索のコストは高くなるだろうが、あなたがいる知っているときにのみ:

+1

私はツリーを使用するとこれより速いと思います。子ノードを共有している場合は、linqのことをする必要はありません。 – DarthVader

+0

一致するノードを収集するためにツリーを何回も通過する必要はありませんか?それは加算しなければならない。 –

3

あなたは簡潔な答えを探しています。テキストのための低レベルでの派手な索引付け(私は特別な.Netクラスについて知らない)がなければ、辞書はあなたの最善の策だと思う。次のようなクエリ:

myDictionary.Where(kvp => kvp.Key.Contains( "11"))。SelectMany(kvp => kvp.Value);

とにかく一般的な部分文字列のためにすべてのキーを検索する必要があります(.Netで提供されていない)ので、LINQはここであなたを傷つけません。

関連する問題