【问题标题】:LINQ grouping multiple fields only if one of the fields is a specific value仅当字段之一是特定值时,LINQ 才对多个字段进行分组
【发布时间】:2017-05-11 12:51:54
【问题描述】:

我正在尝试按 2 个字段(类别,然后是供应商)对列表进行分组,但值不同。如果类别是“01”,则将所有成本相加。如果类别不是“01”,则按类别分组,然后按供应商。

一些演示数据:

List<MyItem> myItemList = new List<MyItem>();
myItemList.Add(new MyItem{Vendor="Ven1", Cost=100, Category="01"});
myItemList.Add(new MyItem{Vendor="Ven2", Cost=10, Category="02"});
myItemList.Add(new MyItem{Vendor="Ven3", Cost=50, Category="02"}));
myItemList.Add(new MyItem{Vendor="Ven2", Cost=40, Category="01"});
myItemList.Add(new MyItem{Vendor="Ven2", Cost=20, Category="01"});
myItemList.Add(new MyItem{Vendor="Ven3", Cost=30, Category="02"});
myItemList.Add(new MyItem{Vendor="Ven1", Cost=10, Category="03"});

我目前在做什么:

List<MyItem> groupedItems = myItemList.GroupBy(a=> new {a.Category, a.Vendor})
                                      .Select(b=> new MyItem{
                                            Vendor = b.First().Vendor,
                                            Cost = b.Sum(c => c.Cost),
                                            Category = b.First().Category
                                       }).ToList();

我正在尝试做什么(也就是我的最佳猜测):

List<MyItem> groupedItems = myItemList.GroupBy(a=> new {a.Category.Where(z=>z.Category.Equals("01:)), a.Vendor})
                                      .Select(b=> new MyItem{
                                            Vendor = b.First().Vendor,
                                            Cost = b.Sum(c => c.Cost),
                                            Category = b.First().Category
                                       }).ToList();

期望的结果:

Category = "01", Vendor = "N/A ", Cost = 160
Category = "02", Vendor = "Ven2", Cost = 10
Category = "02", Vendor = "Ven3", Cost = 80
Category = "03", Vendor = "Ven1", Cost = 10

【问题讨论】:

  • 所以基本上你想将所有 01 类别无条件地分组到供应商,然后其他所有内容都按类别和供应商分组?您能否为您的示例数据显示所需的结果?
  • 为什么是你的成本字符串?
  • 您可以分别处理这些情况,然后合并结果。首先使用 Where 仅获取 01 类别中的项目,然后再获取其余项目。
  • @S.Petrosov 这不仅仅是一个坏例子。我会解决的。
  • @juharr 底部列表,标记为 Desired Result 是我想要的

标签: c# wpf linq


【解决方案1】:

GroupBy 返回具有 2 个字段的匿名类型。返回对象内的值可以是任何值。在这种情况下,如果类别为“01”,则可以更改它们:myItemList.GroupBy(a=&gt; new {a.Category, Vendor= a.Category == "01" ? null : a.Vendor}) 为了与您当前的代码保持一致,该属性被命名为 Vendor,但可以是任何名称。

在您当前的代码中:

List<MyItem> groupedItems = myItemList
    .GroupBy(a => new {a.Category, Vendor = a.Category == "01" ? null : a.Vendor})
    .Select(b => new MyItem
    {
        Vendor = b.First().Vendor,
        Cost = b.Sum(c => c.Cost),
        Category = b.First().Category
    })
    .ToList();

或者稍作改动,代替组的First()值,您可以重用密钥(并一次性实现N\A

List<MyItem> groupedItems = myItemList
      .GroupBy(a=> new {a.Category, Vendor= a.Category == "01" ? "N/A" : a.Vendor})
      .Select(b=> new MyItem{
            Vendor = b.Key.Vendor,
            Cost = b.Sum(c => c.Cost),
            Category = b.Key.Category
       }).ToList();

【讨论】:

  • 或者可能是Vendor = b.First().Category == "01" ? "N\A" : b.First().Vendor,
  • @RufusL 谢谢,在期望的结果中错过了“不适用”的愿望。为此添加了一个选项,仅通过重用密钥而不是重复逻辑。
  • 现在,假设我只需要在类别为“01”的情况下进行分组,而其他所有内容都未分组,使用它如何工作?
  • 你的意思是“01”是一个组,其他的都是一个组吗? .GroupBy(a=&gt; a.Category == "01" ? "1" : null)(或用 Vendor 等应使用的任何值填充密钥)
  • 01 将被分组,其他所有内容均未分组
【解决方案2】:

在一个 Linq-Expression 中做到这一点有点棘手:

var newList = myItemList
    .Where(item => item.Category != "01")
    .GroupBy(item => new {item.Category, item.Vendor})
    .Select(group => new MyItem()
    {
        Vendor = group.Key.Vendor,
        Category = group.Key.Category,
        Cost = group.Sum(item => item.Cost)
    })
    .Union(new[]
    {
        new MyItem()
        {
            Vendor = "N/A",
            Category = "01",
            Cost = myItemList.Where(item => item.Category == "01").Sum(item => item.Cost)
        }
    });

foreach (var loItem in newList)
{
    Debug.WriteLine("Category = {0}, Vendor = {1}, Cost = {2}", 
        loItem.Category, loItem.Vendor, loItem.Cost);
}

【讨论】:

    【解决方案3】:

    目前我的想法是创建两个单独的查询:

    List<MyItem> groupedItemsByCat01 = myItemList.Where(z => z.Category.Equals("01"))
                                                 .GroupBy(a => a.Category)
                                                 .Select(b=> new MyItem{
                                                    Vendor = "N/A",
                                                    Cost = b.Sum(c => c.Cost),
                                                    Category = b.First().Category
                                               }).ToList();
    
    List<MyItem> groupedItemsByOther = myItemList.Where(z => !z.Category.Equals("01"))
                                                 .GroupBy(a => new {a.Category, a.Vendor})
                                                 .Select(b=> new MyItem{
                                                    Vendor = b.First().Vendor,
                                                    Cost = b.Sum(c => c.Cost),
                                                    Category = b.First().Category
                                                 }).ToList();
    
    List<MyItem> final = new List<MyItem>();
    final.AddRange(groupedItemsByCat01);
    final.AddRange(groupedItemsByOther);
    

    【讨论】:

    • 对于Category.Equals("01")Vendor 应该是"N\A"
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-26
    • 1970-01-01
    • 2016-05-09
    • 2018-07-19
    • 2017-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多