使用LINQ对数字进行分组

时间:2013-12-18 04:58:31

标签: c# linq functional-programming

假设我有一个这样的数字列表,

   [3, 3, 1, 2, 3, 2]

我希望按顺序将它们组合在一起,使每组的总和小于或等于5,即正确的答案是:

  [3], [3, 1], [2,3], [2]

有没有办法用Linq来表达这个?

3 个答案:

答案 0 :(得分:9)

易。

var results = xs.Aggregate<int, List<List<int>>>(
    new List<List<int>> { new List<int>() },
    (a, n) =>
    {
        if (a.Last().Sum() + n > 5)
        {
            a.Add(new List<int> { n });
        }
        else
        {
            a.Last().Add(n);
        }
        return a;
    });

所以,从这个:

var xs = new [] { 3, 3, 1, 2, 3, 2, };

我明白了:

result

答案 1 :(得分:0)

不知道这是否与您的想法相近,但让我们一起去吧

List<int> l = new List<int> { 3, 3, 1, 2, 3, 2 };
int[] index = {0};
var s = l.Select((k, i) =>
{
    if (i < index[0])
        return null;

    int total = 0;
    return l.Skip(index[0]).TakeWhile(x =>
    {
        total += x;
        if (total <= 5)
            index[0]++;
        return total <= 5;
    });
}).Where(x => x != null);

foreach (IEnumerable<int> e in s)
{
    foreach (int i in e)
    {
        Console.Write("{0},", i);
    }
    Console.WriteLine();
}

我的推理如下,

  1. 我们必须完成所有项目,因此选择。
  2. 我们必须从列表中获取项目,直到达到总数,因此TakeWhile
  3. 我们必须跟踪列表中的位置,因此索引和返回null。
  4. 我尝试使用int index = 0;初始化,但Resharper呻吟着访问修改后的闭包,并建议将其更改为int[] index = {0};

答案 2 :(得分:0)

您可以尝试使用扩展方法(类似于此,使用您的示例进行测试,但测试的次数不是很多!):

public static class Extensions
{
    public static IEnumerable<IEnumerable<int>> GroupsLessThan(this IEnumerable<int> source, int target)
    {
        var list = new List<int>();
        var runningCount = 0;
        foreach (var element in source)
        {
            if (runningCount + element < target)
            {
                list.Add(element);
                runningCount += element;
            }
            else
            {
                yield return list;
                runningCount = element;
                list = new List<int>{element};
            }
        }

        if (list.Count > 0)
        {
            yield return list;
        }
    }
}
然后用法如下:

var array = new int[] { 3, 3, 1, 2, 3, 2 };
var list = array.GroupsLessThan(6).ToList();