views:

49

answers:

4

Hi, I have the following code :

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

Above as you can see there are multiple users for same key . Now I want to group them and convert the list object to dictionary in which the Key will be the same(1,2 as shown above) but the value will be the collection.Like this:

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

i.e they are grouped now.

How can I achieve that ?

+6  A: 

I would suggest you use a Lookup<TKey, TElement> instead. This data-structure is specifically intended for use as a map from keys to collections of values.

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

Of course, if you do need the dictionary (to allow for mutability perhaps), you can do something like:

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

On another note, theCollection<T>class is not all that useful unless you intend to subclass it. Are you sure you don't just need aList<User>?

Ani
Great! Ani. Just few typos 1.kvp.Key instead of kvp.key 2 if(!outputNeeded.TryGetValue(kvp.key, out userBucketForId) closing bracket missing. But the solutions is great!
Rocky Singh
@Rocky Singh: Glad to help. Thanks for pointing the typos out; fixed
Ani
A: 
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);
    }
}
Daniel Mošmondor
+1  A: 

Given your initial variable "item", and the suggested output variable "outputNeed", this is what you need to do:

NOTE:This is not actual c#/vb code, so please change this pseudo as required (I don't have a VS Studio at hand at the moment):

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

Good luck

Gankbanger
+2  A: 

Here's an example using LINQ's ToDictionary:

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

It results in a Dictionary<int,List<User>>.

cfern
+1: This is a good alternative.
Ani