Test45
Test45

Reputation: 593

LINQ - List to Dictionary, group by multiple properties

I have a HashSet of 2000 items like this (the Index is not a property of the item):

Index    LocationId        UserId   OtherProperty
1                 1             1      abc
2                 1             2      zyx
3                 1             3      nvme
4                 1             4      pcie
5                 2             1      test
6                 2             2      temp
7                 2             3      etc
8                 2             4      hah
...........................................
2000            500             4      last 

If I do:

hashSet.GroupBy(o => o.LocationId)
         .ToDictionary(g => g.Key, g => g.ToList());

I get a dictionary with 500 locations, each containing a list of 4 users.

But I need a dictionary of 2000 items, where the other properties are preserved, each having a list of 4 users. How do I do that?

Upvotes: 0

Views: 55

Answers (1)

kara
kara

Reputation: 3455

Your question is not clear. I did a wild guess what you're trying and set up some examples for you:

static void Main(string[] args)
{
    List<MyClass> list = new List<MyClass>()
    {
        new MyClass() { Index = 1, LocationId = 1, UserId = 1, OtherProperty = "abc" },
        new MyClass() { Index = 2, LocationId = 1, UserId = 2, OtherProperty = "qwe" },
        new MyClass() { Index = 3, LocationId = 1, UserId = 3, OtherProperty = "asd" },
        new MyClass() { Index = 4, LocationId = 1, UserId = 1, OtherProperty = "yxc" },
        new MyClass() { Index = 5, LocationId = 2, UserId = 2, OtherProperty = "acb" },
        new MyClass() { Index = 6, LocationId = 2, UserId = 3, OtherProperty = "ghj" },
        new MyClass() { Index = 7, LocationId = 2, UserId = 1, OtherProperty = "uio" },
        new MyClass() { Index = 8, LocationId = 2, UserId = 2, OtherProperty = "zhn" }
    };

    // Index is Unique => We build a Dictionary with one object per index.
    Dictionary<int, MyClass> dicIndexToObject = list.ToDictionary(d => d.Index);

    // We got multiple objects per Locations => We need a Lookup
    ILookup<int, MyClass> lookupLocationToObject = list.ToLookup(l => l.LocationId);
    // If we ask with a key, we get a List:
    IEnumerable<MyClass> tmp = lookupLocationToObject[1];
    Console.WriteLine("--- What do we have per LocationId? ---");
    foreach (MyClass obj1 in tmp)
    {
        Console.WriteLine(obj1.ToString());
    }

    ILookup<int, MyClass> lookupUserIdToObject = list.ToLookup(l => l.UserId);
    Console.WriteLine("--- What do we have per UserId? ---");
    foreach (MyClass obj2 in lookupUserIdToObject[1])
    {
        Console.WriteLine(obj2.ToString());
    }

    // What if you want to get deeper?

    // What if we want to search for an index within a Location?
    Dictionary<int, Dictionary<int, MyClass>> dicLocationToIndexToObject =
        list.GroupBy(l => l.LocationId) // We group by location
        .ToDictionary(g => g.Key, values => values.ToDictionary(k => k.Index)); // We form the grouping to a dictionary. Instead of accepting a List as value, we form another dictionary

    // if we now want to search for a index in a specific location we do this:
    Console.WriteLine("--- Let's get out object for Index '1' in location '1' ---");
    Dictionary<int, MyClass> tmp2 = dicLocationToIndexToObject[1];
    MyClass obj = tmp2[1];
    Console.WriteLine(obj);

    Console.WriteLine("--- Lets get all objects for UserId '1' in location '2' ---");
    Dictionary<int, ILookup<int, MyClass>> dicLocationToUserIdLookup =
        list.GroupBy(l => l.LocationId) // We group by location
        .ToDictionary(g => g.Key, values => values.ToLookup(k => k.UserId));
    foreach (MyClass obj3 in dicLocationToUserIdLookup[2][1])
    {
        Console.WriteLine(obj3.ToString());
    }
}

public class MyClass
{
    public int Index { get; set; }
    public int LocationId { get; set; }
    public int UserId { get; set; }
    public string OtherProperty { get; set; }

    public override string ToString()
    {
        return String.Format("   Index: {0}, LocationId: {1}, UserId: {2}, OtherProperty: {3}", this.Index, this.LocationId, this.UserId, this.OtherProperty);
    }
}

Upvotes: 1

Related Questions