【问题标题】:How do I order the elements in a group by linq query, and pick the first?如何通过 linq 查询对组中的元素进行排序,然后选择第一个?
【发布时间】:2016-08-11 14:16:35
【问题描述】:

我有一组包含类型、日期和值的数据。

我想按类型分组,对于每个组中的每组值,我想选择日期最新的那个。

这里有一些代码可以工作并给出正确的结果,但我想在一个 linq 查询中而不是在迭代中完成这一切。有什么想法可以通过纯粹的 linq 查询实现与此相同的结果...?

var mydata = new List<Item> {
    new Item { Type = "A", Date = DateTime.Parse("2016/08/11"), Value = 1 },
    new Item { Type = "A", Date = DateTime.Parse("2016/08/12"), Value = 2 },
    new Item { Type = "B", Date = DateTime.Parse("2016/08/20"), Value = 3 },
    new Item { Type = "A", Date = DateTime.Parse("2016/08/09"), Value = 4 },
    new Item { Type = "A", Date = DateTime.Parse("2016/08/08"), Value = 5 },
    new Item { Type = "C", Date = DateTime.Parse("2016/08/17"), Value = 6 },
    new Item { Type = "B", Date = DateTime.Parse("2016/08/30"), Value = 7 },
    new Item { Type = "B", Date = DateTime.Parse("2016/08/18"), Value = 8 },
};

var data = mydata.GroupBy(_ => _.Type);

foreach (var thing in data) {

    #region 
            
    // How can I remove this section and make it part of the group by query above... ?          
    var subset = thing.OrderByDescending(_ => _.Date);
    var top = subset.First();
    
    #endregion
    
    Console.WriteLine($"{thing.Key} {top.Date.ToString("yyyy-MM-dd")} {top.Value}");
}

其中Item定义为:

public class Item {     
    public string Type {get;set;}
    public DateTime Date {get;set;}
    public int Value {get;set;}     
}   
            

预期输出:

A 2016-08-12 2
B 2016-08-30 7
C 2016-08-17 6

【问题讨论】:

  • 使用下划线作为您实际使用的参数的参数名称是非常不寻常的。

标签: c# linq group-by


【解决方案1】:

使用select 得到FirstOrDefault(或First - 因为分组你不会得到一个空)降序排列:

var data = mydata.GroupBy(item => item.Type)
                 .Select(group => group.OrderByDescending(x => x.Date)
                 .FirstOrDefault())
                 .ToList();

SelectMany 加上Take(1)

var data = mydata.GroupBy(item => item.Type)
                 .SelectMany(group => group.OrderByDescending(x => x.Date)
                 .Take(1))
                 .ToList();

【讨论】:

  • 缺少分号
  • @Ehsan - 立即修复
  • 所有答案都很好,很难选择一个...但是您使用 SelectMany 提供了另一种选择...所以我选择这个。谢谢!
  • @BG100 - 哈哈谢谢 :) 非常感谢 - 我喜欢 select manytake 的想法是,如果你需要顶级 X 项目,那就是这样 - 所以只是为了把这个想法传递下去(即使不是针对这种特定情况)
  • 加 1 也用于引用文档站点。
【解决方案2】:

你可以Select有序组的第一个元素:

var topItems = mydata.GroupBy(item => item.Type)
                     .Select(group => group.OrderByDescending(item => item.Date).First())
                     .ToList();

topItems 现在是 List&lt;Item&gt;,仅包含每个 Type 的顶部项目。


您也可以将其检索为Dictionary&lt;string,Item&gt;Type 字符串映射到顶部Item 以获取Type

var topItems = mydata.GroupBy(item => item.Type)
                     .ToDictionary(group => group.Key,
                              group => group.OrderByDescending(item => item.Date).First());

【讨论】:

    【解决方案3】:
    var data = mydata.GroupBy(
        item => item.Type,
        (type, items) => items.OrderByDescending(item => item.Date).First());
    
    foreach (var item in data)
    {
        Console.WriteLine($"{item.Type} {item.Date.ToString("yyyy-MM-dd")} {item.Value}");
    }
    

    【讨论】:

      【解决方案4】:

      按类型分组,对于每个组,按日期降序排列并选择第一个(最新)。

      mydata.GroupBy(i => i.Type).Select(g => g.OrderByDescending(i => i.Date).First());
      

      【讨论】:

      • 已经有很多答案的代码完全相同了,为什么还有一个?是什么让你的与众不同?
      • @sstan 是什么让这些答案与我的不同?我刚刚看到一个问题并正确回答了它
      • 这是我对你的问题 :) 如果很明显其他人已经按照你想要的方式回答了这个问题,而不是发布重复的问题,请点赞他们的答案。
      • @sstan 我不想向你解释任何事情,对不起,要么你是在按照“谁先到这里”的原则来指导自己,要么你是把它当成我的个人。跨度>
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-22
      • 2021-07-28
      • 2015-10-04
      • 1970-01-01
      • 2020-08-02
      • 1970-01-01
      相关资源
      最近更新 更多