2

IEnumerableをルックアップまたは辞書のような構造に変換する最良の方法は何ですか?ただし、値ごとに複数のキーがありますか?
私が探しているのは、これとほぼ同じことを一般的な方法で行うものです。

var wordsByLetter = new Dictionary<char, HashSet<string>>();
foreach (string word in words)
{
    foreach (char letter in word.Distinct())
    {
        if (!wordsByLetter.ContainsKey(letter))
        {
            wordsByLetter.Add(letter, new HashSet<string>());
        }
        wordsByLetter[letter].Add(word);
    }
}

したがって、結果は、使用される各文字をその文字を含む一連の単語にマッピングする辞書です。
たとえば、words含まれている{"foo", "faz", "zoo"}場合、結果の辞書には次のものが含まれます。

'a' -> {"faz"}
'f' -> {"foo", "faz"}
'o' -> {"foo", "zoo"}
'z' -> {"faz", "zoo"}

コード例を拡張メソッドに変えることはできますが、使用する組み込み関数またはより優れたアルゴリズムはありますか?

4

4 に答える 4

5

これが使用する解決策ToDictionaryです:

var wordsByLetter =
    words.SelectMany(word => word.ToCharArray())
         .Distinct()
         .ToDictionary(
            letter => letter,
            letter => words.Where(word => word.Contains(letter)));

単語コレクションは、個別の文字を取得するために1回列挙され、次に各文字に対して1回列挙されるため、コードよりも確かに効率が悪いことに注意してください...


更新:実際には、はるかに効率的な提案があります:

var wordsByLetter = 
   (from word in words
    from letter in word
    group word by letter into grp
    select new
    {
        Letter = grp.Key,
        Words = new HashSet<string>(grp)
    })
    .ToDictionary(x => x.Letter, x => x.Words);

コードとまったく同じ結果が得られるはずです

于 2010-01-12T23:52:50.310 に答える
5

ToLookup は、必要な拡張メソッドです。例えば:

var lookup = (from word in words
              from c in word
              select new { Word = word, Character = c }).ToLookup(x => x.Character, x => x.Word);
于 2010-01-12T23:44:40.727 に答える
1

代わりにTrieを使用することを検討しましたか?

Trie の C# 実装

于 2010-01-12T23:50:01.203 に答える
0
// { foo, faz } -> { f|foo, o|foo, f|faz, a|faz, z|faz }
var pairs = words.SelectMany(w =>
   w.Distinct().Select(l => new { Word = w, Letter = l }));

var map = pairs.ToLookup(p => p.Letter, p => p.Word);
于 2010-01-12T23:57:56.943 に答える