简体   繁体   中英

How to convert flat list to multi-level lookups using linq?

I have list of objects with three keys and I want to convert it to three levels of lookups (or dictionaries):

class MyClass
{
    public int Key1;
    public int Key2;
    public int Key3;
    public float Value;
}
...

IEnumerable<MyClass> table = new List<MyClass>()
{
    new MyClass(){Key1 = 11, Key2 = 21, Key3 = 31, Value = 1},
    new MyClass(){Key1 = 11, Key2 = 21, Key3 = 32, Value = 2},
    new MyClass(){Key1 = 11, Key2 = 22, Key3 = 31, Value = 3},
    new MyClass(){Key1 = 11, Key2 = 23, Key3 = 33, Value = 4},
    new MyClass(){Key1 = 12, Key2 = 21, Key3 = 32, Value = 5},
    new MyClass(){Key1 = 12, Key2 = 22, Key3 = 31, Value = 6}

};

I want the result to be of type:

ILookup<int, ILookup<int, Dictionary<int, float>>>

or

Dictionary<int, Dictionary<int, Dictionary<int, float>>>

I tried:

ILookup<int, MyClass> level1 = table.ToLookup(i => i.Key1, i => i);
ILookup<int, ILookup<int, MyClass>> level2 = level1.ToLookup(
    i => i.Key, i => i.ToLookup(j => j.Key2, j => j));
ILookup<int, ILookup<int, Dictionary<int, float>>> level3 = ?

, but I'm stucked in third level. It's probably a dupe, but what I'm looking for is probably buried under tons of questions about lists of objects with parent-child relation. [1] [2] [3] [4]

It's a bit of an eyeful and not readable at all but this will sort you out:

ILookup<int, ILookup<int, Dictionary<int, float>>> result = table
                .ToLookup(i => i.Key1)
                .ToLookup(i => i.Key, i => i.ToLookup(j => j.Key2)
                .ToLookup(x => x.Key, x => x.ToDictionary(y => y.Key3, y => y.Value)));

If you are certain that every combination of {Key1, Key2, Key3} is unique, you can create a Dictionary. A fetch value from the Dictionary will return one float.

If there might be duplicate combinations of {Key1, Key2, Key3}, then you need to create a LookupTable. A fetch returns the sequence of all original values that have this combination of keys.

For this you need the overload of Enumerable.ToLookup or the overload of Enumerable.ToDictionary with both a keySelector and an ElementSelector.

  • key: new {Key1, Key2, Key3}
  • element: Value

So:

IEnumerable<MyClass> table = ...
var lookupTable = table.ToLookup(

    // parameter keySelector: for every object of MyClass take the keys:
    myObject => new
    {
       Key1 = myObject.Key1,
       Key2 = myObject.Key2,
       Key3 = myObject.Key3,
    },

    // parameter elementSelector: for every object of MyClass take the Value
    myObject => myObject.Value);

ToDictionary is similar:

var dictionary = table.ToLookup(myObject => new
    {
       Key1 = myObject.Key1,
       Key2 = myObject.Key2,
       Key3 = myObject.Key3,
    },
    myObject => myObject.Value);

Usage:

var keyToLookup = new 
{
    Key1 = 7,
    Key2 = 14,
    Key3 = 42,
};

float lookedUpValue = dictionary[keyToLookup];
IEnumerable<lookedUpValues = lookupTable[keyToLookup];

Simple comme bonjour!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM