在LINQ中使用分组依据进行汇总 [英] Aggregation using Group by in LINQ

查看:85
本文介绍了在LINQ中使用分组依据进行汇总的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


我正在尝试对集合运行linq查询,并且我希望结果包含集合中的所有列.但是那些在单行聚合中不唯一的列的值应为null.我怎样才能做到这一点?是否有可用的表达式,我可以使用该表达式返回一行的所有此类列(参与聚合的列除外),该列对于该聚合行是唯一的.

例如:

1)类别:

Hi,
I am trying to run a linq query on a collection and I want the result to contain all the columns in the collection. But those columns that are not unique across a single rows'' aggregation should have the value as null. How can i do this? Is there any expression available using which I can return all such columns for a row (apart from the ones participating in aggregation) which are unique for that aggregated row.

eg:

1) The Class:

public class Person
{ 
string Name 
string Sex
int Age
}





2)集合:





2) The collection:

List<Person> personList



3)集合中的样本数据:




3) Sample data in collection:


Name    Sex       Age
----------------------
Rob     Male       25
Bob     Male       25
Kim     Female     22
Debbie  Female     22
----------------------





var result = from p in personList 
                  group p by new {p.Sex} into g
                  select new {g.Key.Sex, ???????}



我希望能够获得匿名结果,如下所示:



I want to be able to get the anonymous result as follows:

Sex       Age                                    Name
-----------------------------------------------------------------------------------
Male      25(As 25 is unique across Males)       Null (As Name is not unique across Males)
Female    22(As 22 is unique across Females)     Null 
-----------------------------------------------------------------------------------





Does anyone have a way to be able to do this?

推荐答案

这可能很难添加很多属性,但这对于您的特定示例应该有效. br>
This may be difficult to add a lot of properties, but this should work for your specific example.

Dim groups = From g In (From p In personList _<br />             Group p By p.City Into Group) _<br />             Let SingleName As Boolean = (From r In g.Group Select r.Name Distinct).Count <= 1 _<br />             Let SingleAge As Boolean = (From r In g.Group Select r.Age Distinct).Count <= 1 _<br />             Select New Person() With {.Sex = g.Sex, _<br />                                       .Name = If(SingleName, g.Group.First.Name, Nothing), _<br />                                       .Age = If(SingleAge, g.Group.First.Age, Nothing)}<br />For Each g In groups<br />    Console.WriteLine("{0}, {1}, {2}", g.Sex, g.Age, g.Name)<br />Next


进一步考虑,我能够将用于检查组中相同值的属性的逻辑提取到扩展方法中.这将简化查询.


Upon further consideration, I was able to extract the logic for checking properties for the same value within a group into an extension method. This will simplify the query a little bit.


Dim lcGroups = From g In (From p In personList _<br />                          Group By p.Sex Into Group) _<br />               Select New Person() With {.Sex = g.Sex, _<br />                                         .Name = g.Group.SameOrDefault(Function(p) p.Name), _<br />                                         .Age = g.Group.SameOrDefault(Function(p) p.Age)}<br /><br /><System.Runtime.CompilerServices.Extension()> _<br />Public Function SameOrDefault(Of TInput, TOutput)(ByVal items As IEnumerable(Of TInput), _<br />                                                  ByVal valueSelector As Func(Of TInput, TOutput)) As TOutput<br />    Return SameOrDefault(items, valueSelector, EqualityComparer(Of TOutput).Default)<br />End Function<br /><br /><System.Runtime.CompilerServices.Extension()> _<br />Public Function SameOrDefault(Of TInput, TOutput)(ByVal items As IEnumerable(Of TInput), _<br />                                                  ByVal valueSelector As Func(Of TInput, TOutput), _<br />                                                  ByVal comparer As IEqualityComparer(Of TOutput)) As TOutput<br />    If items Is Nothing Then Return Nothing<br />    If valueSelector Is Nothing Then <br />        Throw New ArgumentNullException("valueSelector", "A value selector must be provided.")<br />    End If<br />    If comparer Is Nothing Then comparer = EqualityComparer(Of TOutput).Default<br /><br />    Dim result As TOutput = valueSelector(items.First())<br />    For Each i In items<br />        If Not comparer.Equals(result, valueSelector(i)) Then Return Nothing<br />    Next<br />    Return result<br />End Function



在大多数情况下,第一次重载将起作用,但是如果您想比较复杂的类型或使用一些非默认值比较,例如向量的大小,第二个重载将派上用场.



The first overload will work for most cases, but if you wanted to compare complex types or use some non-default comparison, such as the magnitude of a vector, the second overload would come in handy.


这篇关于在LINQ中使用分组依据进行汇总的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆