我有一个这样的数据集:
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
最大的GroupName
,并将它们传递给一个委托函数。如下所示:
'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()
来仅过滤掉最大的MemberValue
。
我该怎么做才能正确过滤这个数据集并将其传递到我的函数中呢?
3条答案
按热度按时间2w3rbyxf1#
您可以使用下面的Linq来实现这一点。
首先,您必须按
GroupValue
分组,然后按Key
的降序对组进行排序(也就是GroupValue
),然后取第一个,现在你就有了最大值为GroupValue
的所有行。然后,将GroupName
上的行进行分组,并从这些组中按降序对MemberValue
进行排序,并获取First
行以获取每个组中的行如果data
是空的,我也会在FirstOrDefault
后面使用C#6的null条件运算符?.
。如果你没有使用C#6,那么你需要预先处理这种情况,你可以直接使用First
。xxls0lw82#
所以基本上你需要的是,把你的数据元素分成具有相同
GroupName
值的组,从每个组中你要取一个元素,也就是具有最大MemberValue
值的那个。每当您有一个项目序列,并且希望根据序列中项目的一个或多个属性的值将此序列划分为组时,您可以使用Enumerable.GroupBy
'GroupBy'将您的序列作为输入和一个额外的输入参数:一个函数,用于选择要比较的项的哪些属性,以决定该项显示在哪个组中。
在您的示例中,您希望将序列分成组,其中组中的所有元素都具有相同的
GroupName
。它从mySequence中的每个元素获取属性GroupName,并将该元素放入具有该GroupName值的元素组中。
使用示例数据,您将有三个组:
每个组都有一个Key属性,其中包含您的选择值。该键标识该组,并保证在组集合中是唯一的。因此,您将有一个Key ==“Group1”的组,一个Key ==“Group2”的组,依此类推。
除
Key
外,每一个群都是群中元素的序列(注:组是一个可枚举序列,而不是:它有一个可枚举序列。第二步是从每个组中获取组中
MemberValue
值最大的元素。为此,您将按属性MemberValue的值降序对组中的元素进行排序,并获取第一个元素。结果:从按memberValue降序排序的每个组中,取第一个元素,它应该是最大的元素。
如果您只需要memberValue值最大的元素,那么对整个组进行排序的效率不是很高。
voj3qocg3#
解决此问题更简单的方法是使用新的(.NET 6)
MaxBy
LINQ运算符沿着GroupBy
和Select
运算符:这是一个简单但内存效率不高的解决方案。原因是它在幕后生成了一个完整的
Lookup<TKey, TSource>
结构,它是一个字典行容器,包含与每个键关联的所有记录。该结构是在开始比较每个分组中包含的元素之前生成的,以便选择最大的元素。在大多数情况下,这种低效率并不是问题,因为记录并不多,而且它们已经存储在内存中。但是如果你有一个真正延迟的可枚举序列,其中包含大量的元素,你可能会耗尽内存。在这种情况下,你可以使用下面的
GroupMaxBy
运算符。这个运算符只在内存中存储每个键当前最大的元素:用法示例:
相反的
GroupMinBy
可以通过用<=
替换>=
来类似地实现。下面是两种方法在内存效率方面的差异:
输出量:
Try it on Fiddle。