2

IEnumerable将 an转换为类似查找或类似字典的结构但每个值有多个键的最佳方法是什么?
我正在寻找的是与此大致相同的东西,并且以一种通用的方式:

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

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 回答
5

Here's a solution using ToDictionary :

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

Note that it's certainly less efficient than your code, since the words collection is enumerated once to get the distinct letters, then once for each letter...


Update: actually I have a much more efficient suggestion :

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);

It should give exactly the same result as your code

于 2010-01-12T23:52:50.310 回答
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 回答