Группировка пар KeyValue в словарь - PullRequest
3 голосов
/ 20 октября 2010

У меня есть следующий код:

using System.Collections.Generic;


public class Test
{
    static void Main()
    {

        var items = new List<KeyValuePair<int, User>>
                        {
                            new KeyValuePair<int, User>(1, new User {FirstName = "Name1"}),
                            new KeyValuePair<int, User>(1, new User {FirstName = "Name2"}),
                            new KeyValuePair<int, User>(2, new User {FirstName = "Name3"}),
                            new KeyValuePair<int, User>(2, new User {FirstName = "Name4"})
                        };

    }
}
public class User
{
    public string FirstName { get; set; }
}

Выше, как видите, есть несколько пользователей для одного и того же ключа.Теперь я хочу сгруппировать их и преобразовать объект списка в словарь, в котором ключ будет таким же (1,2, как показано выше), но значением будет коллекция.теперь они сгруппированы.

Как мне этого добиться?

Ответы [ 4 ]

6 голосов
/ 20 октября 2010

Вот пример использования ToDictionary LINQ:

var output = items.GroupBy(kvp => kvp.Key)
                  .ToDictionary(group => group.Key,
                                group => group.Select(kvp => kvp.Value).ToList());

В результате получается Dictionary<int,List<User>>.

6 голосов
/ 20 октября 2010

Я бы предложил вам использовать Lookup<TKey, TElement>. Эта структура данных специально предназначена для использования в качестве карты от ключей до коллекций значений.

//uses Enumerable.ToLookup: the Id is the key, and the User object the value
var outputNeeded = items.ToLookup(kvp => kvp.Key, kvp => kvp.Value);

Конечно, если вам нужен словарь (возможно, для обеспечения изменчивости), вы можете сделать что-то вроде:

var outputNeeded = new Dictionary<int, Collection<User>>();

foreach(var kvp in list)
{
   Collection<User> userBucketForId;

   if(!outputNeeded.TryGetValue(kvp.Key, out userBucketForId)) 
   {
       // bucket doesn't exist, create a new bucket for the Id, containing the user
       outputNeeded.Add(kvp.Key, new Collection<User> { kvp.Value });
   }
   else 
   {   // bucket already exists, append user to it.
       userBucketForId.Add(kvp.Value);
   }
}

С другой стороны, класс Collection<T> не так уж и полезен, если только вы не собираетесь его подклассировать. Вы уверены, что вам не нужен List<User>?

1 голос
/ 20 октября 2010

Учитывая вашу начальную переменную "item" и предлагаемую выходную переменную "outputNeed", это то, что вам нужно сделать:

ПРИМЕЧАНИЕ. Это не фактический код на c # / vb, поэтому, пожалуйста, измените это псевдо при необходимости (на данный момент у меня под рукой нет VS Studio):

foreach (KeyValuePair<int, User> pair in items) 
{
    //add a new collection if this is the first time you encounter the key
    if (! outputNeed.Contains(pair.Key) 
    {
        outputNeed[pair.Key] = new ArrayList<User>());
    }
    //add the user to the matching collection
    outputNeed.Add(pair.Key, pair.User);
}

Удачи

0 голосов
/ 20 октября 2010
foreach (var u in items)
{
    if (outputNeed.Contains(u.Key)) {
        outputNeed[u.Key].Add(u.Value);
    }
    else {
        Collection<User> a=new Collection<User>();
        a.Add(u.Value);
        outputNeed.Add(u.Key,a);
    }
}
...