2017-06-06 6 views
3

Ich habe zwei Arrays von gleicher Länge und ich möchte sie irgendwie beide auf einmal mit der Reduce-Methode verarbeiten. Etwas wie:Kann ich array.prototype.reduce() verwenden, um zwei Arrays gleichzeitig zu verarbeiten?

var arr1 = [2, 3, 4, 5, 6]; 
var arr2 = [5, 10, 4, 9, 5]; 
var productSum = arr1.reduce(function(sumOfProducts, item, secondArrayItem) { 
    /* here I would like to multiply item from arr1 by the item from arr2 at the same index */ 
    return sumOfProducts + item * secondArrayItem; 
}, 0, arr2) 
console.log(productSum); // 131 

Eine Option wäre natürlich das richtige Element für den Zugriff von arr2currentIndex verwenden, aber diese Lösung ist hässlich wie ich eine Variable außerhalb des Bereichs der Funktion zugreifen.

Mein spezifischer Anwendungsfall ist, dass ich ein Array mit Ressourcen wie var resources = [2, 5, 4, 6, 2] habe, und ich möchte prüfen, ob jedes Element höher ist als entsprechende Ressourcenkosten in einem anderen Array wie var cost = [3, 1, 0, 0, 1].

Gibt es eine nette Lösung dafür mit der reduce() Funktion?

+2

Sie würden dies normalerweise tun, indem Sie die 2 Listen zusammen zippen und dann die gezippte Liste reduzieren. Ich weiß nicht, wie man Listen in JS idiomatisch zippen kann. – Carcigenicate

+4

"* Diese Lösung ist hässlich, da ich auf eine Variable außerhalb des Bereichs der Funktion zugreife." "Ich sehe nicht, was hässlich ist, wir tun dies die ganze Zeit, wenn wir auf Globals zugreifen oder Schließungen verwenden. Wichtig ist nur, dass die Variable konstant ist. Was wirklich hässlich an dieser Lösung ist, ist a) es ist nicht symmetrisch (der Zugriff auf arr1 funktioniert anders als der Zugriff auf arr2) und b) wir haben nicht sichergestellt, dass die Arrays die gleiche Länge haben, also wissen wir nicht ob arr2 [i] 'greift auf einen gültigen Index zu. – Bergi

Antwort

1

Der üblicher Weg, die ich kenne, dies zu tun ist, um die zwei Listen in eine Liste von entsprechenden Paaren („zippen“) zu kombinieren, dann reduziert die kombinierten Listen:

var zipped = zip(arr1, arr2) 

reduce((acc, [x, y]) => (Use x and y), 
       zipped) 

Für Implementierungen von zip finden this question.

(Wird Syntax überprüfen, wenn ich aus der Transit bekam)

+0

Ist das der Weg, selbst für große Arrays zu gehen? Ich möchte kein ganz neues Array erstellen, wenn ich nur die Werte beider Arrays auf einmal durchlaufen möchte. – BoltKey

+3

@BoltKey Wenn Sie mit riesigen Arrays arbeiten wollen, sollten Sie 'reduce' vergessen und eine einfache for-Schleife verwenden. –

+1

@BoltKey Dies ist ein viel besserer Ansatz im Umgang mit faulen Strukturen, ich gebe es zu. Es wird 1 Iteration benötigt, um zu zippen, dann eine weitere zu reduzieren und eine Zwischenliste zu erstellen, also nein, das wird leider nicht performant. – Carcigenicate

2

Ramda verwenden Sie die beiden Listen ersten zip kann, und dann verwenden, reduzieren Destrukturierung die Array-Elemente zu extrahieren und sie passieren als Argument für den Rückruf:

const reduceTwo = (callback, initialValue, arr1, arr2) => 
 
    R.reduce((acc, [x, y]) => callback(acc, x, y), initialValue, R.zip(arr1, arr2)); 
 

 
const arr1 = [2, 3, 4, 5, 6]; 
 
const arr2 = [5, 10, 4, 9, 5]; 
 
console.log(reduceTwo((acc, x, y) => acc + x * y, 0, arr1, arr2));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.24.1/ramda.min.js"></script>

+2

Die Verwendung einer ganzen Bibliothek nur für zip-Funktion scheint mir ein bisschen überflüssig ... – BoltKey

+0

@BoltKey Warum? Wenn Sie das Webpack mit Tree Shaking verwenden, um Ihren Code zu bündeln, hat dies keine negativen Auswirkungen auf die Leistung. –

0

Sie tun können als mit reiner JS folgt;

var arr1 = [2, 3, 4, 5, 6], 
 
    arr2 = [5, 10, 4, 9, 5], 
 
    result = arr1.reduce((r,c,i) => (r.sum = r.sum ? r.sum + c * r[i] : c * r[i], r), arr2.slice()).sum; 
 
console.log(result);

I .slice()arr2, um es mit einer Zustandsvariablen nicht mutieren noch kann man ohne Schneiden immer noch, wenn Sie eine for in Schleife arr2 danach nicht oder so ...

Verwandte Themen