Преобразование IEnumerable в поиск с несколькими ключами на значение - PullRequest
2 голосов
/ 13 января 2010

Как лучше всего преобразовать 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 ]

5 голосов
/ 13 января 2010

Вот решение, использующее 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);

Это должно дать точно такой же результат, как ваш код

5 голосов
/ 13 января 2010

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 голос
/ 13 января 2010

Рассматривали ли вы вместо этого Trie ?

C # реализация Trie

0 голосов
/ 13 января 2010
// { 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...