将IEnumerable转换为每个值具有多个键的查找

时间:2010-01-12 23:41:55

标签: c# linq data-structures dictionary lookup

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 个答案:

答案 0 :(得分: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);

答案 1 :(得分:5)

以下是使用ToDictionary的解决方案:

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

请注意,它的效率肯定低于您的代码,因为单词集合枚举一次以获取不同的字母,然后每个字母一次......


更新:实际上我提出了更有效的建议:

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

它应该提供与您的代码完全相同的结果

答案 2 :(得分:1)

您是否考虑过使用Trie

C# implementation of a Trie

答案 3 :(得分: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);
相关问题