【发布时间】:2016-04-06 21:05:00
【问题描述】:
我正在尝试找到一种方法来使用 LINQ 对列表进行分组,不仅通过 Foo 对象(EmployeeId、CompanyId 和 GroupId)的属性,而且仅在 Baz 对象的 StartDate 和 EndDate 属性完全相同的情况下对它们进行分组.目标是按 EmployeeId、CompanyId 和 GroupId 分组,并将 Bars 集合组合成所有分组记录的聚合。
因此,如果 List 具有三个对象,并且第一个对象上的 Bars 集合都是 BazId=1,第二个 BazId=2 和第三个 BazId=3,我希望 List 包含两个对象,其中一个是 Bars BazIds 为 1 和 3 的集合和另一个 BazIds 为 2 的 Bars 集合(因为 1 和 3 共享相同的开始/结束日期,如下所述)。
我希望这是有道理的。我已经清醒太久了,所以如果不清楚,请告诉我,我会尽力澄清。
到目前为止我所拥有的是:
var result = foos.GroupBy(g => new { g.CompanyId, g.EmployeeId, g.GroupId })
.Select(g => new Foo(g.Key.CompanyId, g.Key.EmployeeId, g.Key.GroupId)
{
Bars = g.SelectMany(x => x.Bars)}
).ToList();
但是,这会忽略相应 Baz 对象的 StartDate/EndDate 属性。我只想对 Foo 对象的记录进行分组,其 Bars 集合的 BazId 共享相同的开始/结束日期。
编辑:给定 Bars 集合中的所有 Bar 对象都将具有相同的 BazId 是一个业务规则
public class Foo {
public int EmployeeId { get; set; }
public int CompanyId { get; set;
public int GroupId { get; set; }
public List<Bar> Bars { get; set; }
}
public class Bar {
public BazId { get; set; }
public string Name { get; set; }
}
public class Baz {
public int Id { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
var baz = new List<Baz> {
new Baz {
Id = 1,
StartDate = DateTime.Now,
EndDate = DateTime.Now.AddMonths(1)
},
new Baz {
Id = 2,
StartDate = DateTime.Now.AddMonths(-1),
EndDate = DateTime.Now.AddMonths(1)
},
new Baz {
Id = 3,
StartDate = DateTime.Now,
EndDate = DateTime.Now.AddMonths(1)
},
}
解决方案 根据@jdweng 的评论,我最终得出的结论是:
var result = foos.GroupBy(g => g, new FooComparer())
.Select(g => new Foo(g.Key.CompanyId, g.Key.EmployeeId, g.Key.GroupId)
{
Bars = g.SelectMany(x => x.Bars)}
).ToList();
在FooComparer 中,我实现了IEqualityComparer<Foo> 并创建了Equals 和GetHashCode 方法,通过检查每个Baz 集合来确定两者是否相等。
【问题讨论】:
-
尝试使用方法 CompareTo() 向 IComparable 类添加继承。 Linq Groupby 将使用 CompareTo 方法进行分组。
-
@jdweng - 将此作为答案,我会将其标记为已接受。效果很好,是一个非常干净的解决方案。