【问题标题】:LINQ GroupBy child collection propertiesLINQ GroupBy 子集合属性
【发布时间】: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&lt;Foo&gt; 并创建了EqualsGetHashCode 方法,通过检查每个Baz 集合来确定两者是否相等。

【问题讨论】:

  • 尝试使用方法 CompareTo() 向 IComparable 类添加继承。 Linq Groupby 将使用 CompareTo 方法进行分组。
  • @jdweng - 将此作为答案,我会将其标记为已接受。效果很好,是一个非常干净的解决方案。

标签: c# linq


【解决方案1】:

尝试使用方法 CompareTo() 向 IComparable 类添加继承。 Linq Groupby 将使用 CompareTo 方法进行分组

【讨论】:

    【解决方案2】:

    您似乎必须将开始日期和结束日期包括在分组中。为此,您必须加入 Baz。

    var bazs = new List<Baz> {
        new Baz {
            Id = 1,
            StartDate = DateTime.Today,
            EndDate = DateTime.Today.AddMonths(1)
        },
        new Baz {
            Id = 2,
            StartDate = DateTime.Today.AddMonths(-1),
            EndDate = DateTime.Today.AddMonths(1)
        },
        new Baz {
            Id = 3,
            StartDate = DateTime.Today,
            EndDate = DateTime.Today.AddMonths(1)
        }
    };
    
    List<Foo> foos = new List<Foo>{
        new Foo
        {
            EmployeeId = 1,
            CompanyId = 2,
            GroupId = 3,
            Bars = new List<Bar> {
                new Bar { BazId = 1 },
                new Bar { BazId = 2 },
                new Bar { BazId = 3 }
            }
        }
    };
    
    var result = (from extendedBar in foos.SelectMany(f => f.Bars.Select(b => new { Bar = b, f.EmployeeId, f.CompanyId, f.GroupId }))
                  join baz in bazs
                  on extendedBar.Bar.BazId equals baz.Id
                  select new { extendedBar.Bar, extendedBar.EmployeeId, extendedBar.CompanyId, extendedBar.GroupId, baz.StartDate, baz.EndDate })
                    .GroupBy(o => new { o.EmployeeId, o.CompanyId, o.GroupId, o.StartDate, o.EndDate })
                    .Select(g => new Foo { EmployeeId = g.Key.EmployeeId, CompanyId = g.Key.CompanyId, GroupId = g.Key.GroupId, Bars = g.Select(o => o.Bar).ToList() })
                 .ToList();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-25
      • 1970-01-01
      相关资源
      最近更新 更多