【问题标题】:LINQ group by date and then order by property, to get the highest amount?LINQ 按日期分组,然后按属性排序,以获得最高金额?
【发布时间】:2019-11-05 08:59:49
【问题描述】:

假设这个模型:

public class Model
{
    public DateTime Created { get; set; }
    public int Quota { get; set; }
}

我需要指定一年中的特定月份,并提取Quota 的摘要,但我只需要在该月的每一天抓取一个(列表中的最大值为 31,最小值为 28,具体取决于日期),并且该条目必须是 Quota 最高的条目。示例:

[{
  created: "10/1/2019",
  quota: 5
}, {
  created: "10/1/2019",
  quota: 6
}, {
  created: "10/2/2019",
  quota: 1
}]

在那个例子中,我会得到两个项目:

[{
  created: "10/1/2019",
  quota: 6
}, {
  created: "10/2/2019",
  quota: 1
}]

因为Quota = 6 高于Quota = 5 并且它们在同一日期(10 月 1 日)。

public List<Model> GetMonthlyData(int year, int month)
{
    var list = await _dbContext
        .Where(x => x.Created.Year == year && x.Created.Month == month)
        .GroupBy(x => x.Created.Day)
        .OrderByDescending(x => x.Quota)
        .Select(x => x.First())
        .ToListAsync();

    return list;
}

我想要这样的东西。按天分组,按降序排列(因此第一项具有最高配额),选择组中的第一项,并将它们转换为列表。但是,我无法弄清楚如何做到这一点。我敢肯定这真的很简单,但我看不到我的错误在哪里。

【问题讨论】:

  • GroupBy 返回一个复合对象:一个键(即日期)和与该键相关的项目的枚举(即原始项目)。
  • GroupBy(...).Select(grp =&gt; grp.OrderByDescending(x =&gt; x.Quota).First()).ToList()

标签: c# linq


【解决方案1】:

您需要在 Select() 下方使用 GroupBy

 var test = mList
        .Where(x => x.Created.Year == year && x.Created.Month == month)   //Filter your record based on condition
        .GroupBy(x => x.Created.Day) //Group by Created.Day
        .Select(x => x.Aggregate((z1, z2) => z1.Quota > z2.Quota ? z1 : z2))   // Aggreate function to Get object with max Qouta
        .ToList();   //Convert into List

输出:

10/1/2019    6
10/2/2019    1

我使用了下面的 linq 函数,

.Where() :在您的情况下,根据条件过滤记录的 Where 子句是 x.Created.Year == year &amp;&amp; x.Created.Month == month

.GroupBy() :基于谓词的组元素,即基于x.Created.Day的组过滤记录

.Aggregate() :对元素应用指定的逻辑,这里我使用ternary operator 来获取基于最高Qouta 的整个对象

.Select() : 获取新形式的对象。

.Net Fiddle

【讨论】:

  • 啊,是的,在 Select 中执行 OrderByDescending。那是我错的地方。非常感谢!
  • 我在小提琴中努力写选择语句,感谢@Jimi 他的评论给了我提示
  • Max() flattens 将类型转换为一个值,因此您可能需要一个投影。这取决于预期的结果。 OrderBy().Last() 返回原始类型(不过还有其他方法)。
  • @Jimi,我在写小提琴时意识到,我更新为使用.Aggregate
【解决方案2】:

这里有两个选项。

 var list = data
        .GroupBy(x => x.Created.Date)
        .Select( g => g.OrderByDescending(x => x.Quota).First());

选项 2。

var list = data
        .GroupBy(x => x.Created.Date)
        .Select( g => new { Created = g.Key, Quota = g.Max( x => x.Quota)});

测试

var json = @"[{
    created: ""10/1/2019"",
    quota: 5
}, {
    created: ""10/1/2019"",
    quota: 6
}, {    
    created: ""10/2/2019"",
    quota: 1
},{
    created: ""10/2/2019"",
    quota: 7
}]";

var data = JsonConvert.DeserializeObject<List<Model>>(json);

 var list = data
        .GroupBy(x => x.Created.Date)
        .Select( g => g.OrderByDescending(x => x.Quota).First());

 foreach( var l in list ) Console.WriteLine($"{l.Created} with {l.Quota}");
// .NETCoreApp,Version=v3.0
1/10/2019 00:00:00 with 6
2/10/2019 00:00:00 with 7

【讨论】:

    猜你喜欢
    • 2018-04-15
    • 2020-05-20
    • 2021-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多