将键值对分组到Dictionary

时间:2010-10-20 12:50:12

标签: c# generics dictionary key-value

我有以下代码:

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

上面您可以看到有多个用户使用相同的密钥。现在我想将它们分组并将列表对象转换为字典,其中Key将是相同的(1,2如上所示)但值将是集合。就像这样:

 var outputNeed = new Dictionary<int, Collection<User>>();
        //Output:
        //1,Collection<User>
        //2,Collection<User>

现在它们已经分组了。

我怎样才能做到这一点?

5 个答案:

答案 0 :(得分:6)

我建议您改用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 :(得分:6)

以下是使用LINQ的ToDictionary的示例:

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

结果为Dictionary<int,List<User>>

答案 2 :(得分:1)

鉴于您的初始变量“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);
}
祝你好运

答案 3 :(得分:0)

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

答案 4 :(得分:0)

这是我的解决方案:

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

var result = (
    from item in items
    group item.Value by item.Key into grouped
    select grouped
).ToDictionary(g => g.Key, g => g);

DotNetFiddle