【发布时间】:2014-01-06 03:32:53
【问题描述】:
假设我有一个这样的数字列表,
[3, 3, 1, 2, 3, 2]
我想将它们按顺序分组在一起,使每组的总和小于或等于五,即正确答案是:
[3], [3, 1], [2,3], [2]
有没有办法用 Linq 来表达?
【问题讨论】:
标签: c# linq functional-programming
假设我有一个这样的数字列表,
[3, 3, 1, 2, 3, 2]
我想将它们按顺序分组在一起,使每组的总和小于或等于五,即正确答案是:
[3], [3, 1], [2,3], [2]
有没有办法用 Linq 来表达?
【问题讨论】:
标签: c# linq functional-programming
不知道这是否接近您的想法,但让我们试一试
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();
}
我的推理如下,
我最初尝试使用int index = 0;,但Resharper 抱怨访问修改后的闭包并建议将其更改为int[] index = {0};
【讨论】:
简单。
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, };
我明白了:
【讨论】:
您可以尝试一种扩展方法(类似这样的方法,用您的示例进行了测试,但没有比这更多的测试!):
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();
【讨论】: