LINQ表达式:指定最大分组大小

本文关键字:表达式 LINQ | 更新日期: 2023-09-27 18:16:18

在LINQ中是否有一种优雅的方式来执行以下操作,或者我应该为此编写一个扩展

我有一个对象列表,需要按开始日期分组

让说

09.00,13.00,13.00,13.00,

15.00,
var groupedStartDates = startdate.groupby(x => x.StartDate);

我需要组的最大大小为2。

预期结果

var groupedStartDates = startDate.GroupBy(x => x.StartDate);
List
    list1 {09.00}
    list2 {13.00; 13.00}
    list3 {13.00}
    list4 {15.00}

LINQ表达式:指定最大分组大小

在初始分组之后,您可以按索引(在组中)除以2进行分组,然后使用SelectMany来平化返回。

var result = startDate.GroupBy(x => x.StartDate)
                      .SelectMany(grp => grp.Select((x,i) => new{x,i})
                                            .GroupBy(a => a.i / 2)
                                            .Select(sgrp => sgrp.Select(a => a.x)));

下面是正在发生的事情的分解。注意大括号表示集合,方括号表示具有多个属性的对象。

初始数据

09.00, 13.00, 13.00, 13.00, 15.00

GroupBy(x => x.StartDate)

[关键:09.00,{09.00}],[关键:13.00,{13.00,13.00,13.00}],[关键:15.00,{15.00}]

现在它将对每一组进行操作,但我将显示每一步对所有组的结果。Select((x,i) => new{x,i})

{[x: 09.00,我:0]},{[x: 13.00,我:0],[x: 13.00,我:1],[x: 13.00,我:2]},{[x: 15.00,我:0]}

GroupBy(a => a.i / 2)

{(关键:0,{[x: 09.00,我:0]}]},{(关键:0,{[x: 13.00,我:0],[x: 13.00,我:1]}],[关键:1、{[x: 13.00,我:2]}},{(关键:0,{[x: 15.00,我:0]}}

.Select(sgrp => sgrp.Select(a => a.x))

{{09.00}}, {{13.00, 13.00}, {13.00}}, {{15.00}}

最后SelectMany会把它压平为。

{09.00}, {13.00, 13.00}, {13.00}, {15.00}

请注意,每一行代表一个集合,但我没有在它们周围加上花括号,因为我觉得这会使它更难阅读。

或者使用扩展方法

public static IEnumerable<IEnumerable<T>> Bin<T>(this IEnumerable<T> items, int binSize)
{
    return items
        .Select((x,i) => new{x,i})
        .GroupBy(a => a.i / binSize)
        .Select(grp => grp.Select(a => a.x));
}

你可以把它做得更好一点。

var result = startDate
    .GroupBy(x => x.StartDate)
    .SelectMany(grp => grp.Bin(2));

更新:在。net 6中,他们添加了新的Linq方法Chuck,它与上面的Bin方法做同样的事情。现在你可以输入

var result = startDate
    .GroupBy(x => x.StartDate)
    .SelectMany(grp => grp.Chunk(2));

如果我正确理解你的问题,你可以使用Take:

var result= startDate.GroupBy(x => x.StartDate)
                     .Select(x => x.Take(2))
                     .ToList();

每个组最多包含2个成员,组中的其他项将不返回。