在LINQ中使用分组依据进行汇总 [英] Aggregation using Group by in 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屋!