如何汇总数组列表

我有一个List myList,我知道所有int []数组都是相同的长度 – 为了参数,让我们说我有500个数组,每个数组长2048个元素。 我想总结所有500个这些数组,给我一个数组,长度为2048个元素,其中每个元素是所有其他数组中所有相同位置的总和。

显然,这在命令式代码中是微不足道的:

int[] sums = new int[myList[0].Length]; foreach(int[] array in myList) { for(int i = 0; i < sums.Length; i++) { sums[i] += array[i]; } } 

但我想知道是否有一个很好的Linq或Enumerable.xxx技术?

编辑:哎哟…当我不看时,这变得有点困难。 不断变化的要求可能是真正的PITA。

好的,所以把arrays中的每个位置都加起来吧:

 var sums = Enumerable.Range(0, myList[0].Length) .Select(i => myList.Select( nums => nums[i] ).Sum() ); 

这有点难看……但我认为声明版本会更糟。

编辑:为了感兴趣,我把它留在这里,但接受的答案要好得多。

编辑:好的,我之前的尝试(参见编辑历史)基本上是完全错误的…

可以用一行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; }); 

我没有测试过,但我认为它应该可行。 我不会推荐它。 SelectMany将所有数据展平为一系列对 – 每对都是值,其索引在其原始数组中。

Aggregate步骤完全是非纯粹的 – 它通过在正确的位置添加正确的值来修改其累加器。

除非有人能想出一种基本上转动原始数据的方法(此时我的早期答案就是你想要的),我怀疑你最好不采用非LINQ方式。

这适用于任何2个序列,而不仅仅是数组:

 var myList = new List { 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 

好吧,假设我们可以假设数组列表中每个位置的整数总和本身都适合int(这是一个狡猾的假设,但无论如何我都会使它更容易):

 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(); 

编辑 – D’哦。 出于某种原因。选择最初避开了我。 那有点好。 这是一个轻微的黑客攻击,因为sumTotal既作为输入(在聚合调用中使用的数组中的位置)又作为生成的IEnumerable中的输出总和,这是违反直觉的。

坦率地说,这比用老式的方式做得更加可怕:-)

这是一个用性能来交换Linq语句的简单性。

 var colSums = from col in array.Pivot() select col.Sum(); 

  public static class LinqExtensions { public static IEnumerable> Pivot( this IList array ) { for( int c = 0; c < array[ 0 ].Length; c++ ) yield return PivotColumn( array, c ); } private static IEnumerable PivotColumn( IList array, int c ) { for( int r = 0; r < array.Count; r++ ) yield return array[ r ][ c ]; } } 

我会这样做…但是这个解决方案可能实际上非常慢,因此您可能希望在将其部署到性能关键部分之前运行基准测试。

 var result = xs.Aggregate( (a, b) => Enumerable.Range(0, a.Length).Select(i => a[i] + b[i]).ToArray() );