【问题标题】:Select records with max property value per groupLINQ - 选择每组具有最大属性值的记录
【发布时间】:2017-10-03 22:22:57
【问题描述】:

我有一个这样的数据集:

GroupName   GroupValue   MemberName   MemberValue
'Group1'    1            'Member1'    1
'Group1'    1            'Member2'    2
'Group2'    2            'Member3'    3
'Group2'    2            'Member4'    2
'Group3'    2            'Member5'    4
'Group3'    2            'Member6'    1

我要选择的是每个GroupName 具有最大MemberValue 的行,但仅适用于具有最大GroupValue 的那些GroupNames,并将它们传递给委托函数。像这样:

'Group2'    2            'Member3'    3
'Group3'    2            'Member5'    4

到目前为止,我已经尝试过这种格式...

data.Where(maxGroupValue => 
    maxGroupValue.GroupValue == data.Max(groupValue => groupValue.GroupValue))
.Select(FunctionThatTakesData)

...但这只是给了我 Group2 和 Group3 的每个成员。我尝试在Select() 之前放置一个GroupBy(),但这会将输出变成IGrouping<string, DataType>,所以FunctionThatTakesData() 不知道如何处理它,我不能再做一个Where()只过滤掉最大的MemberValues。

我该怎么做才能正确过滤此数据集并将其传递到我的函数中?

【问题讨论】:

    标签: c# .net linq group-by


    【解决方案1】:

    所以基本上你想要的是将你的数据元素分成具有相同GroupName 值的组。从每个组中你想取一个元素,即属性MemberValue 的最大值。

    每当您有一个项目序列,并且您想根据您使用的序列中项目的一个或多个属性的值将该序列分组时Enumerable.GroupBy

    'GroupBy' 将您的序列作为输入和一个额外的输入参数:该函数用于选择您想要比较的项目的哪些属性,以决定您希望项目出现在哪个组中。

    在您的情况下,您希望将序列分成组,其中组中的所有元素都具有相同的GroupName

    var groups = mySequence.GroupBy(element => element.GroupName);
    

    它的作用是从 mySequence 中的每个元素中获取属性 GroupName,并将此元素放入具有此 GroupName 值的一组元素中。

    使用您的示例数据,您将拥有三个组:

    • 具有 GroupName == "Group1" 的所有元素的组。您序列的前两个元素将在此组中
    • 具有 GroupName == "Group2" 的所有元素的组。您序列的第三个和第四个元素将在此组中
    • 具有 GroupName == "Group3" 的所有元素的组。您序列的最后两个元素将在此组中

    每个组都有一个属性 Key,其中包含您的选择值。此键标识组,并保证在您的组集合中是唯一的。所以你会有一个 Key == "Group1" 的组,一个 Key == "Group2" 的组,等等。

    除了Key,每个组都是组中元素的序列(注意:组IS是可枚举的序列,而不是:它HAS是可枚举的顺序。

    您的第二步是从每个组中取出组中MemberValue 值最大的元素。为此,您可以按属性 MemberValue 的降序对组中的元素进行排序,然后取第一个。

    var myResult = mySequence.GroupBy(element => element.GroupName)
        // intermediate result: groups where all elements have the same GroupName
        .Select(group => group.OrderByDescending(groupElement => groupElement.MemberValue)
        // intermediate result: groups where all elements are ordered in descending memberValue
        .First();
    

    结果:从每个按成员值降序排列的组中,取第一个元素,应该是最大的一个。

    如果您只想要memberValue 中值最大的元素,那么对整个组进行排序不是很有效。可以找到答案 here on StackOverflow

    【讨论】:

    • 这为您提供了每个GroupName 和最大MemberValue。 OP 只想要最大 GroupValue 的行,然后每个 MemberName 最大 MemberValue
    【解决方案2】:

    您可以使用以下 Linq 做到这一点。

    var results = data.GroupBy(r = r.GroupValue)
        .OrderByDescending(g => g.Key)
        .FirstOrDefault()
        ?.GroupBy(r => r.GroupName)
        .Select(g => g.OrderByDescending(r => r.MemberValue).First());
    

    首先,您必须在GroupValue 上进行分组,然后按Key(即GroupValue)降序排列组,然后取第一个。现在您拥有最大为GroupValue 的所有行。然后你将它们分组到GroupName 上,并从这些组中按降序排列MemberValue,并取First 行以获取每个GroupName 组中最大MemberValue 的行。另外我在FirstOrDefault 之后使用C# 6 空条件运算符?.,以防data 为空。如果您不使用 C# 6,那么您需要预先处理这种情况,您可以改用 First

    【讨论】:

    • 谢谢!现在,假设每个分组可以有多个具有相同值的成员......我应该只使用Where() 代替First()吗?
    • 在这种情况下,您希望.SelectMany(g => g.GroupBy(r => r.MemberValue).OrderByDescending(sg => sg.Key).First()) 替换最后一行。
    • 天才!谢谢!
    猜你喜欢
    • 1970-01-01
    • 2022-11-07
    • 2021-03-29
    • 1970-01-01
    • 2012-05-18
    • 2019-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多