LINQ:GroupBy,每组最大计数

JKJ*_*KJK 10 linq

我有一个重复的数字列表:

Enumerable.Range(1,3).Select(o => Enumerable.Repeat(o, 3)).SelectMany(o => o)
// {1,1,1,2,2,2,3,3,3}
Run Code Online (Sandbox Code Playgroud)

我将它们分组并获得发生的数量:

Enumerable.Range(1,3).Select(o => Enumerable.Repeat(o, 3)).SelectMany(o => o)
    .GroupBy(o => o).Select(o => new { Qty = o.Count(), Num = o.Key })

Qty   Num
3     1
3     2
3     3
Run Code Online (Sandbox Code Playgroud)

我真正需要的是将每组的数量限制为某个数字.如果限制为2,则上述分组的结果将是:

Qty   Num
2     1
1     1
2     2
1     2
2     3
1     3
Run Code Online (Sandbox Code Playgroud)

因此,如果Qty = 10且limit为4,则结果为3行(4,4,2).每个数字的数量与示例中的不相等.整个列表的指定数量限制相同(根据数量不同).

谢谢

Luk*_*keH 5

其他一些答案使 LINQ 查询比它需要的复杂得多。使用foreach循环当然更快、更有效,但 LINQ 替代方案仍然相当简单。

var input = Enumerable.Range(1, 3).SelectMany(x => Enumerable.Repeat(x, 10));
int limit = 4;

var query =
    input.GroupBy(x => x)
         .SelectMany(g => g.Select((x, i) => new { Val = x, Grp = i / limit }))
         .GroupBy(x => x, x => x.Val)
         .Select(g => new { Qty = g.Count(), Num = g.Key.Val });
Run Code Online (Sandbox Code Playgroud)


Aar*_*ght 4

最近出现了一个类似的问题,询问如何在 SQL 中执行此操作 - 没有真正优雅的解决方案,除非这是 Linq to SQL 或实体框架(即转换为 SQL 查询),否则我真的建议您不要这样做尝试使用 Linq 解决这个问题,并编写一个迭代解决方案;它将变得更加高效并且更容易维护。

也就是说,如果您绝对必须使用基于集合的(“Linq”)方法,这是您可以做到的一种方法:

var grouped =
    from n in nums
    group n by n into g
    select new { Num = g.Key, Qty = g.Count() };

int maxPerGroup = 2;
var portioned =
    from x in grouped
    from i in Enumerable.Range(1, grouped.Max(g => g.Qty))
    where (x.Qty % maxPerGroup) == (i % maxPerGroup)
    let tempQty = (x.Qty / maxPerGroup) == (i / maxPerGroup) ? 
        (x.Qty % maxPerGroup) : maxPerGroup
    select new
    {
        Num = x.Num,
        Qty = (tempQty > 0) ? tempQty : maxPerGroup
    };
Run Code Online (Sandbox Code Playgroud)

与更简单、更快的迭代版本相比:

foreach (var g in grouped)
{
    int remaining = g.Qty;
    while (remaining > 0)
    {
        int allotted = Math.Min(remaining, maxPerGroup);
        yield return new MyGroup(g.Num, allotted);
        remaining -= allotted;
    }
}
Run Code Online (Sandbox Code Playgroud)