C# 如何对数组列表<>求和
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/311710/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I sum a list<> of arrays
提问by Will Dean
I have a List< int[] > myList, where I know that all the int[] arrays are the same length - for the sake of argument, let us say I have 500 arrays, each is 2048 elements long. I'd like to sum all 500 of these arrays, to give me a single array, 2048 elements long, where each element is the sum of all the same positions in all the other arrays.
我有一个 List< int[] > myList,其中我知道所有 int[] 数组的长度都相同——为了论证,假设我有 500 个数组,每个数组的长度为 2048 个元素。我想对所有 500 个数组求和,得到一个数组,长度为 2048 个元素,其中每个元素是所有其他数组中所有相同位置的总和。
Obviously this is trivial in imperative code:
显然,这在命令式代码中是微不足道的:
int[] sums = new int[myList[0].Length];
foreach(int[] array in myList)
{
for(int i = 0; i < sums.Length; i++)
{
sums[i] += array[i];
}
}
But I was wondering if there was a nice Linq or Enumerable.xxx technique?
但我想知道是否有一个不错的 Linq 或 Enumerable.xxx 技术?
采纳答案by Mark Brackett
Edit: Ouch...This became a bit harder while I wasn't looking. Changing requirements can be a real PITA.
编辑:哎哟...这在我不看的时候变得有点难了。不断变化的需求可以成为真正的 PITA。
Okay, so take each position in the array, and sum it:
好的,所以取数组中的每个位置,然后求和:
var sums = Enumerable.Range(0, myList[0].Length)
.Select(i => myList.Select(
nums => nums[i]
).Sum()
);
That's kind of ugly...but I think the statement version would be even worse.
这有点难看……但我认为声明版本会更糟。
回答by Jon Skeet
EDIT: I've left this here for the sake of interest, but the accepted answer is much nicer.
编辑:为了感兴趣,我把它留在这里,但接受的答案要好得多。
EDIT: Okay, my previous attempt (see edit history) was basically completely wrong...
编辑:好的,我之前的尝试(见编辑历史)基本上是完全错误的......
You cando this with a single line of LINQ, but it's horrible:
你可以用一行 LINQ来做到这一点,但这太可怕了:
var results = myList.SelectMany(array => array.Select(
(value, index) => new { value, index })
.Aggregate(new int[myList[0].Length],
(result, item) => { result[item.index] += value; return result; });
I haven't tested it, but I think it should work. I wouldn't recommend it though. The SelectMany flattens all the data into a sequence of pairs - each pair is the value, and its index within its original array.
我还没有测试过,但我认为它应该可以工作。不过我不会推荐它。SelectMany 将所有数据平展为一系列对 - 每对是值,以及它在原始数组中的索引。
The Aggregate step is entirely non-pure - it modifies its accumulator as it goes, by adding the right value at the right point.
Aggregate 步骤完全是非纯的 - 它通过在正确的点添加正确的值来随时修改其累加器。
Unless anyone can think of a way of basically pivoting your original data (at which point my earlier answer is what you want) I suspect you're best off doing this the non-LINQ way.
除非有人能想到一种基本上旋转原始数据的方法(此时我之前的答案就是您想要的),我怀疑您最好以非 LINQ 方式执行此操作。
回答by Neil Hewitt
OK, assuming we can assume that the sum of the ints at each position over the list of arrays will itself fit into an int (which is a dodgy assumption, but I'll make it anyway to make the job easier):
好吧,假设我们可以假设数组列表上每个位置的整数总和本身适合一个整数(这是一个狡猾的假设,但无论如何我都会让它更容易):
int[] sums =
Enumerable.Range(0, listOfArrays[0].Length-1).
Select(sumTotal =>
Enumerable.Range(0, listOfArrays.Count-1).
Aggregate((total, listIndex) =>
total += listOfArrays[listIndex][sumTotal])).ToArray();
EDIT - D'oh. For some reason .Select evaded me originally. That's a bit better. It's a slight hack because sumTotal is acting as both the input (the position in the array which is used in the Aggregate call) and the output sum in the resulting IEnumerable, which is counter-intuitive.
编辑 - 哦。出于某种原因, .Select 最初避开了我。这样好一些。这是一个小问题,因为 sumTotal 既作为输入(在 Aggregate 调用中使用的数组中的位置)又作为结果 IEnumerable 中的输出总和,这是违反直觉的。
Frankly this is far more horrible than doing it the old-fasioned way :-)
坦率地说,这比老式的方式要可怕得多:-)
回答by Konrad Rudolph
I would do it as follows … but this solution might actually be very slow so you might want to run a benchmark before deploying it in performance-critical sections.
我会这样做……但这个解决方案实际上可能非常慢,因此您可能希望在将其部署到性能关键部分之前运行基准测试。
var result = xs.Aggregate(
(a, b) => Enumerable.Range(0, a.Length).Select(i => a[i] + b[i]).ToArray()
);
回答by Bryan Watts
This works with any 2 sequences, not just arrays:
这适用于任何 2 个序列,而不仅仅是数组:
var myList = new List<int[]>
{
new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 },
new int[] { 10, 20, 30, 40, 50, 60, 70, 80, 90 }
};
var sums =
from array in myList
from valueIndex in array.Select((value, index) => new { Value = value, Index = index })
group valueIndex by valueIndex.Index into indexGroups
select indexGroups.Select(indexGroup => indexGroup.Value).Sum()
foreach(var sum in sums)
{
Console.WriteLine(sum);
}
// Prints:
//
// 11
// 22
// 33
// 44
// 55
// 66
// 77
// 88
// 99
回答by jyoung
Here is one that trades the Linq statement simplicity with performance.
这是一个用性能来交换 Linq 语句的简单性。
var colSums =
from col in array.Pivot()
select col.Sum();
public static class LinqExtensions {
public static IEnumerable<IEnumerable<T>> Pivot<T>( this IList<T[]> array ) {
for( int c = 0; c < array[ 0 ].Length; c++ )
yield return PivotColumn( array, c );
}
private static IEnumerable<T> PivotColumn<T>( IList<T[]> array, int c ) {
for( int r = 0; r < array.Count; r++ )
yield return array[ r ][ c ];
}
}
回答by DDRider62
It can be done with Zip and Aggregate. The question is so old that probably Zip was not around at the time. Anyway, here is my version, hoping it will help someone.
它可以通过 Zip 和 Aggregate 来完成。这个问题太老了,当时可能 Zip 还不存在。无论如何,这是我的版本,希望它会帮助某人。
List<int[]> myListOfIntArrays = PopulateListOfArraysOf100Ints();
int[] totals = new int[100];
int[] allArraysSum = myListOfIntArrays.Aggregate(
totals,
(arrCumul, arrItem) => arrCumul.Zip(arrItem, (a, b) => a + b))
.ToArray();