簡體   English   中英

如何匯總數組列表<\\ n>

[英]How do I sum a list<> of arrays

我有一個List <int []> 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。

好吧,所以取數組中的每個位置,並總結:

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<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

好吧,假設我們可以假設數組列表中每個位置的整數總和本身都適合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<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 ];
    }
}

我會這樣做...但是這個解決方案可能實際上非常慢,因此您可能希望在將其部署到性能關鍵部分之前運行基准測試。

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

它可以使用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();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM