2016-12-20 2 views
1

In meinem Poker App ich eine Reihe von Händen habe, jede Hand zu seiner Anordnung von zufällig ausgewählten Kartenobjekten mit Wert und Farbe:Nested foreach-Schleifen unerwartetes Verhalten

[ [ { value: 5, suit: 's' }, 
    { value: 4, suit: 's' }, 
    { value: 6, suit: 'c' }, 
    { value: 11, suit: 'd' }, 
    { value: 12, suit: 'c' } ], 
    [ { value: 9, suit: 'd' }, 
    { value: 12, suit: 'h' }, 
    { value: 8, suit: 'c' }, 
    { value: 12, suit: 's' }, 
    { value: 2, suit: 's' } ], 
    [ { value: 4, suit: 'h' }, 
    { value: 6, suit: 's' }, 
    { value: 10, suit: 'c' }, 
    { value: 3, suit: 'd' }, 
    { value: 7, suit: 'd' } ] ] 

Um die Hände zur Auswertung vorbereitet Ich mag zurückkehren ein Array von Handobjekten mit jeweils einem Array von values und suits. So würde der Ausgang sein:

[ 
    { 
    values: [5, 4, 6, 11, 12], 
    suits: ['s', 's', 'c', 'd', 'c'] 
    },  
    { 
    values: [9, 12, 8, 12, 2], 
    suits: ['d', 'h', 'c', 's', 's'] 
    }, 
    { 
    values: [4, 6, 10, 3, 7], 
    suits: ['h', 's', 'c', 'd', 'd'] 
    } 
] 

Ich versuche, verschachtelte zu verwenden foreach-Schleifen, dies zu erreichen, etwa so:

let temp = [] 
hands.forEach((el) => { 
    temp = el 
    el = {} 
    el.values = [] 
    el.suits = [] 
    temp.forEach((obj) => { 
    el.values.push(obj.value) 
    el.suits.push(obj.suit) 
    console.log(el) //expected output 
    }) 
    console.log(el) //expected output 
}) 
console.log(hands) //same as original 

jedoch als Kommentare Umriss, es verhält sich wie erwartet, bis die Schleife hat beendet, wobei sich hands überhaupt nicht geändert hat. Was fehlt mir hier? in der Anordnung, die wiederum an die variable el

Antwort

4

forEach nicht das Array ändern, auf dem es hieß, es iteriert einfach das Array eine Funktion für jedes Element aufrufen. Wenn Sie ein neues Array innerhalb dieser Funktion aufbauen wollen, tun nur so

var newArray = []; 
hands.forEach((el) => { 
    var newValue = // do something here 
    newArray.push(newValue); 
}); 

Ich denke, was Sie versuchen, dies zu tun ist:

var hands = [ [ { value: 5, suit: 's' }, 
 
    { value: 4, suit: 's' }, 
 
    { value: 6, suit: 'c' }, 
 
    { value: 11, suit: 'd' }, 
 
    { value: 12, suit: 'c' } ], 
 
    [ { value: 9, suit: 'd' }, 
 
    { value: 12, suit: 'h' }, 
 
    { value: 8, suit: 'c' }, 
 
    { value: 12, suit: 's' }, 
 
    { value: 2, suit: 's' } ], 
 
    [ { value: 4, suit: 'h' }, 
 
    { value: 6, suit: 's' }, 
 
    { value: 10, suit: 'c' }, 
 
    { value: 3, suit: 'd' }, 
 
    { value: 7, suit: 'd' } ] ]; 
 

 
let newValues = [] 
 
hands.forEach((el) => { 
 
    var temp = {values:[], suits:[]}; 
 
    el.forEach((obj) => { 
 
    temp.values.push(obj.value) 
 
    temp.suits.push(obj.suit) 
 
    
 
    }) 
 
    newValues.push(temp); 
 
}) 
 
console.log(newValues) // NOT same as original

Es gibt viele Wege, um das gleiche zu erreichen, das Beste, was ich mir vorstellen kann, ist unten - und vermeidet die doppelte hand.map in anderen Antworten gesehen (was ziemlich ineffizient ist).

var hands = [ [ { value: 5, suit: 's' }, 
 
    { value: 4, suit: 's' }, 
 
    { value: 6, suit: 'c' }, 
 
    { value: 11, suit: 'd' }, 
 
    { value: 12, suit: 'c' } ], 
 
    [ { value: 9, suit: 'd' }, 
 
    { value: 12, suit: 'h' }, 
 
    { value: 8, suit: 'c' }, 
 
    { value: 12, suit: 's' }, 
 
    { value: 2, suit: 's' } ], 
 
    [ { value: 4, suit: 'h' }, 
 
    { value: 6, suit: 's' }, 
 
    { value: 10, suit: 'c' }, 
 
    { value: 3, suit: 'd' }, 
 
    { value: 7, suit: 'd' } ] ]; 
 

 
let newValues = hands.map(h => { 
 
     return h.reduce((p,c) => { 
 
      p.values.push(c.value); 
 
      p.suits.push(c.suit); 
 
      return p; 
 
     },{values:[], suits:[]}); 
 
    }); 
 

 
console.log(newValues) // NOT same as original

+1

Obwohl das gesagt, warum weiter 'forEach' verwenden? Dies ist, was wir der map API für map hinzugefügt haben. –

+0

Ich stimme zu, ich würde dies nicht so schreiben, wie es das OP getan hat, aber um den Code so originalgetreu wie möglich zu halten ... – Jamiec

+0

Wenn der ursprüngliche Code ein schlechter Code ist, sind wir hier, um Leuten zu helfen schreibe auch besseren Code. Je früher OP lernt, die Karte für diese Dinge zu verwenden, desto besser werden ihre Code-Beiträge für die Welt im Allgemeinen sein, einschließlich zukünftiger Antworten von ihnen auf SO. –

1
hands.forEach((el) => { 

Sie jedes Objekt zuweisen.

el = {} 

Sie überschreiben die Variableel mit einem Verweis auf ein neues Objekt.

el ist nicht mehr mit dem ursprünglichen Wert verbunden.

Sie sind nur ersetzt den Wert el. Die Eigenschaften im Array zeigen immer noch auf die ursprünglichen Objekte.


Um die Objekte im ursprünglichen Array zu ändern, müssen Sie ihnen explizit ein neues Objekt zuweisen.

hands.forEach((originalValue, index, array) => { 
    // originalValue is what you used to call `temp` 
    // Just make `el` a new object 
    var el = {}; 
    // Put it in the array 
    array[index] = el; 
    // Then continue as before 
1

Lassen Sie JavaScript dies für Sie tun, anstatt eine Menge Code zu schreiben, durch die Nutzung der map Funktion nehmen, die Unterstützung Arrays:

let rewritten = data.map(hand => { 
    return { 
    values: hand.map(card => card.value), 
    suits: hand.map(card => card.suit), 
    } 
}); 

(mit dem äußeren { return und } in der Pfeil-Funktion nicht notwendig, wenn Sie alle auf die gleiche Zeile setzen, aber für die Zwecke einer Antwort, die es natürlich weit weniger lesbar macht)

Dies nimmt Ihre ursprünglichen Daten, die bereits und Array-Größe auf Händen (drei in diesem Fall), und wendet dann eine Transformation auf jede Hand. Insbesondere erstellt es ein neues Objekt, bei dem das Array von "Werten und Anzügen" in ein Array von "gerechten Werten" umgewandelt wurde, unter Verwendung von map und eines Arrays von "just suits", ebenfalls unter Verwendung von map.

Arrays in JavaScript sind mit einer Reihe von Funktionen zum Packen/Entpacken/Iterieren/Transformieren ausgestattet, und es lohnt sich, diese zu lesen. Sie ermöglichen Ihnen, große Dinge mit sehr wenig Code zu tun.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array ist eine Lektüre wert, wenn Sie die API für Arrays seit einiger Zeit oder nie mehr gelesen haben. Es erklärt auch, wie man zum Beispiel recude benutzt, was benutzt werden kann, um diesen Code effizienter zu machen (siehe oben die Antwort von Jamiec).

+2

Persoanlly, denke, das ist ein * schrecklicher * Weg, um das Problem zu lösen - du übertreibst unnötigerweise zweimal in jeder Schleife, was nicht großartig ist - lerne es Verwenden Sie 'reduce' – Jamiec

+0

noch besser, freuen uns auf Ihre Antwort mit reduzieren statt. –

+0

Ihr Wunsch ist mein Befehl. – Jamiec

1

Sie könnten die Werte direkt in einem Objekt für die Eigenschaften zuordnen.

var data = [[{ value: 5, suit: 's' }, { value: 4, suit: 's' }, { value: 6, suit: 'c' }, { value: 11, suit: 'd' }, { value: 12, suit: 'c' }], [{ value: 9, suit: 'd' }, { value: 12, suit: 'h' }, { value: 8, suit: 'c' }, { value: 12, suit: 's' }, { value: 2, suit: 's' }], [{ value: 4, suit: 'h' }, { value: 6, suit: 's' }, { value: 10, suit: 'c' }, { value: 3, suit: 'd' }, { value: 7, suit: 'd' }]], 
 

 
result = data.map(a => (
 
    { 
 
    values: a.map(b => b.value), 
 
    suits: a.map(b => b.suit) 
 
    }) 
 
); 
 

 
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sie könnten eine weniger Iteration Stil verwenden.

var data = [[{ value: 5, suit: 's' }, { value: 4, suit: 's' }, { value: 6, suit: 'c' }, { value: 11, suit: 'd' }, { value: 12, suit: 'c' }], [{ value: 9, suit: 'd' }, { value: 12, suit: 'h' }, { value: 8, suit: 'c' }, { value: 12, suit: 's' }, { value: 2, suit: 's' }], [{ value: 4, suit: 'h' }, { value: 6, suit: 's' }, { value: 10, suit: 'c' }, { value: 3, suit: 'd' }, { value: 7, suit: 'd' }]], 
 
    keys = ['value', 'suit'], 
 
    result = data.map(
 
     a => a.reduce(
 
      (r, b) => (keys.forEach(k => r[k + 's'].push(b[k])), r), { values: [], suits: [] } 
 
     ) 
 
    ); 
 

 
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

1

Sie brauchen nur ein Objekt mit zwei Eigenschaften (Werte und Anzüge) vor der zweiten Schleife zu erzeugen und ihn in dem Ergebnis nach dieser zweiten Schleife wie diese injizieren:

var hands = [[{ value: 5, suit: 's' }, { value: 4, suit: 's' }, { value: 6, suit: 'c' }, { value: 11, suit: 'd' }, { value: 12, suit: 'c' }], [{ value: 9, suit: 'd' }, { value: 12, suit: 'h' }, { value: 8, suit: 'c' }, { value: 12, suit: 's' }, { value: 2, suit: 's' }], [{ value: 4, suit: 'h' }, { value: 6, suit: 's' }, { value: 10, suit: 'c' }, { value: 3, suit: 'd' }, { value: 7, suit: 'd' }]]; 
 
var output = []; 
 
hands.forEach(x => { 
 
    var temp = {values: [], suits: []}; 
 
    x.forEach(y => { 
 
    temp.values.push(y.value); 
 
    temp.suits.push(y.suit); 
 
    }) 
 
    output.push(temp); 
 
}); 
 
console.log(output);