将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"}
我可以将我的代码示例转换为扩展方法,但是有内置函数或更好的算法可供使用吗?
答案 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?
答案 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);