如何使用 linq 将平面列表转换为多级查找?

Posted

技术标签:

【中文标题】如何使用 linq 将平面列表转换为多级查找?【英文标题】:How to convert flat list to multi-level lookups using linq? 【发布时间】:2021-02-16 15:48:52 【问题描述】:

我有一个包含三个键的对象列表,我想将其转换为三个级别的查找(或字典):

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

;

我希望结果是类型:

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

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

我试过了:

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 = ?

,但我被困在第三级。这可能是一个骗局,但我正在寻找的可能隐藏在关于具有父子关系的对象列表的大量问题中。 [1][2][3][4]

【问题讨论】:

我相信那些关键的重复正在通过查找和字典拒绝您的想法。您正在寻找的可能是一个加权图或只是反映关系的二维数组。如果您真的想构建该结构,则需要在此 Dictionary&lt;int, Dictionary&lt;int, Dictionary&lt;int, float&gt;&gt;&gt; 结构的第一个关键参数中创建唯一标识符 【参考方案1】:

它有点眼花缭乱,根本不可读,但这会让你明白:

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

【讨论】:

【参考方案2】:

如果您确定 Key1, Key2, Key3 的每个组合都是唯一的,则可以创建字典。从 Dictionary 中获取值将返回一个浮点数。

如果 Key1, Key2, Key3 的组合可能重复,则需要创建一个 LookupTable。提取返回具有此键组合的所有原始值的序列。

为此,您需要 the overload of Enumerable.ToLookup 或 the overload of Enumerable.ToDictionary 以及 keySelector 和 ElementSelector。

键:new Key1, Key2, Key3 元素:Value

所以:

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 类似:

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

用法:

var keyToLookup = new 

    Key1 = 7,
    Key2 = 14,
    Key3 = 42,
;

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

简单的祝你好运!

【讨论】:

以上是关于如何使用 linq 将平面列表转换为多级查找?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 linq 将列表中的列表转换为单个列表 [重复]

LINQ 将项目列表转换为具有冗余值的行的查找

如何使用 Lambda 或 Linq 将匿名类型转换为原始类型成员

尝试从 Excel 2013 批量导入到 TFS 时,如何将我的平面列表转换为树列表?

将平面集合转换为一对多 C#/Linq

C# LINQ 在列表中查找重复项