2016-06-14 5 views
4

Ich versuche ein Musikspiel zu erstellen, bei dem ich aus einem einfachen 2D-Array ein 3D-Array generieren muss. Der Plan war, zu kopieren und die 2D-Array 4 mal in das 3D-Array einfügen, bevor es zu ändern, wie es gezeigt:Erzeugen eines 3D-Arrays aus einem 2D-Array

var note3base = [ 
["C", "E", "G"], 
["C#", "E#", "G#"], 
["Db", "F", "Ab"], 
["D", "F#", "A"], 
["Eb", "G", "Bb"], 
["E", "G#", "B"], 
["F", "A", "C"], 
["F#", "A#", "C#"], 
["Gb", "Bb", "Db"], 
["G", "B", "D"], 
["Ab", "C", "Eb"], 
["A", "C#", "E"], 
["Bb", "D", "F"], 
["B", "D#", "F#"], 
["Cb", "Eb", "Gb"] 
]; 

var note3 = new Array(4); 

for (h=0;h<note3.length;h++){ 
note3[h] = note3base; 
} //creates 4 copies of note3base in a 3d-array to be modified 

for (i=0;i<note3[0].length;i++){ 
note3[1][i][1] = flat(note3[1][i][1]); //minor 
note3[2][i][1] = flat(note3[2][i][1]); 
note3[2][i][2] = flat(note3[2][i][2]); //dim 
note3[3][i][2] = sharp(note3[3][i][2]); //aug 
} //how did everything become the same? 

Das Problem scheint jetzt zu sein, dass die for Schleife um die Methode zu jedem einzelnen Array zu gelten scheint (0 bis 3).

Die gewünschte Ausgabe für Note3 [0] [1] wäre CEG, Note3 [1] [1] wäre C Eb G, Note [2] [1] wäre C Eb Gb, Note [3] [ 1] wäre CEG #.

Jede Hilfe wird sehr geschätzt!

Ich habe die (Arbeits-) scharf und flach Methoden unten als Referenz enthalten:

function sharp(note){ 
    var newnote; 
    if (note.charAt(1) == "#"){ 
    newnote = note.replace("#", "x"); 
    } else if (note.charAt(1) == "b"){ 
    newnote = note.replace("b", ""); 
    } else { 
    newnote = note + "#"; 
    } 
    return newnote; 
} 

function flat(note){ 
    var newnote; 
    if (note.charAt(1) == "#"){ 
    newnote = note.replace("#", ""); 
    } else { 
    newnote = note + "b"; 
    } 
    return newnote; 
} 
+0

Beachten Sie, dass Ihre 'flach()' Funktion einen 'sonst if' Fall wie Ihre' scharf braucht() 'Funktion, zur Deckung Doppel-Wohnungen. – nnnnnn

Antwort

3

Das Problem ist, dass, wenn Sie eine Variable gleich einem Array wie folgt vergeben:

someVar = someArray; 

... es ist nicht eine Kopie des Arrays macht, es schafft eine zweite Referenz auf das gleiche Array. (Dies gilt für alle Objekte und Arrays sind eine Art von Objekt.) Also nach der Schleife, wo Sie gesagt haben:

for (h=0;h<note3.length;h++){ 
    note3[h] = note3base; 

... alle Elemente in note3 auf den gleichen zugrunde liegenden Array verweisen.

Um eine aktuelle Kopie zu machen, können Sie manuell alle Elemente über mit einer Schleife kopieren können, oder Sie die .slice() method verwenden können Sie eine Kopie zu machen:

for (h=0;h<note3.length;h++){ 
    note3[h] = note3base.slice(); 
} 

Aber das wird nur die Hälfte lösen das Problem, weil note3base selbst Verweise auf andere Arrays enthält, und .slice() kopiert nur diese Referenzen. Das heißt, obwohl sich note3[0] und note3[1] (und 2 und 3) auf unterschiedliche Arrays beziehen, beziehen sich note3[0][0] und note3[1][0] und note3[2][0] und note3[3][0] auf das gleiche Array ["C", "E", "G"]. (Und so fort.)

Sie benötigen, was eine "tiefe Kopie" genannt wird. Man könnte es mit einer verschachtelten Schleife tun:

for (h=0;h<note3.length;h++){ 
    // create this element as a new empty array: 
    note3[h] = []; 
    // for each 3-note array in note3base 
    for (var k = 0; k < note3base.length; k++) { 
    // make a copy with slice 
    note3[h][k] = note3base[k].slice(); 
    } 
} 

alles, was gesagt hat, ich denke, dass ein einfacher Weg, um die ganze Sache zu tun wäre, anstatt ein note3baseVariable zu haben, die auf ein Array verweist, macht es zu einem Funktion, die ein neues Array zurück:

function makeNote3Array() { 
    return [ 
    ["C", "E", "G"], 
    ["C#", "E#", "G#"], 
    ["Db", "F", "Ab"], 
    ["D", "F#", "A"], 
    ["Eb", "G", "Bb"], 
    ["E", "G#", "B"], 
    ["F", "A", "C"], 
    ["F#", "A#", "C#"], 
    ["Gb", "Bb", "Db"], 
    ["G", "B", "D"], 
    ["Ab", "C", "Eb"], 
    ["A", "C#", "E"], 
    ["Bb", "D", "F"], 
    ["B", "D#", "F#"], 
    ["Cb", "Eb", "Gb"] 
    ]; 
} 

Da die Funktion ein Array-Literal verwendet wird es eine brandneue Reihe von Arrays erstellen jedes Mal, sie aufgerufen wird. So können Sie das folgende tun, ohne die Notwendigkeit für .slice() oder verschachtelte Schleifen:

var note3 = new Array(4); 
for (h=0;h<note3.length;h++){ 
    note3[h] = makeNote3Array(); 
} 
+0

das ist eine wirklich klare Erklärung! mit einer noch besseren Lösung! Danke vielmals! –

3

TL; DR, dies tun:

for (h=0;h<note3.length;h++){ 
    note3[h] = note3base.slice(0); 
} 

Erläuterung:

Das Problem ergibt sich aus dem Unterschied zwischen der Weitergabe von etwas 'Wert' und 'durch Referenz' in Javascri pt.

Wenn Sie einen Grundwert einer Variablen zuweisen, wie a = "string";, und dann, dass wie b = a; auf eine andere Variable, abtreten, wird der Wert auf b bestanden ‚by-value‘: seine Wert-b zugeordnet ist, aber b verweist auf einen anderen Teil des Speichers. Es gibt nun zwei "String" -Werte im Speicher, einen für a und einen für b.

a = "string"; 
b = a; 
a = "gnirts"; 
console.log(b); // "string" 

Dies funktioniert nicht für nicht-primitive Typen wie Arrays. Hier wird der Wert b 'by reference' übergeben, was bedeutet, dass immer noch nur ein [1, 2, 3] Array im Speicher ist und sowohl a als auch b darauf zeigen. Das bedeutet, dass Sie ein Element in a ändern, es wird sich auch für b ändern, da sie dasselbe Array im Speicher referenzieren. So können Sie diese:

a = [1, 2, 3]; 
b = a; 
a[0] = "hello"; 
console.log(b); // ["hello", 2, 3] 

b[0] geändert hat, weil es die gleiche Stelle im Speicher als a[0] verweist. Um dieses Problem zu umgehen, müssen wir eine Kopie von notepad3base erstellen, wenn Sie sie an eine andere Variable übergeben, anstatt sie nur als Referenz zu übergeben. Wir können dies mit note3base.slice(0) wie oben tun.

Edit: mehr lesen here

Verwandte Themen