2016-06-14 143 views
4

我正尝试创建一个音乐游戏,我必须从基本2D阵列生成3D阵列。该计划是复制和4次进入3D阵列粘贴2D阵列修改它之前,如图所示:从2D阵列生成3D阵列

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? 

现在这个问题似乎是该for循环似乎将该方法应用到每个单独阵列( 0至3)。 Note3 [0] [1]的期望输出为CEG,note3 [1] [1]为C Eb G,note [2] [1]为C Eb Gb,note [3] [ 1]将是CEG#。

任何帮助,非常感谢!

我已经包括下面的(工作)锋利,方法以供参考:

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

请注意,你的'平()'函数需要一个'其他if'情况下喜欢你'锐()'函数,覆盖双层公寓。 – nnnnnn

回答

3

的问题是,当你将一个变量等于一个这样的数组:

someVar = someArray; 

...它不会使数组的副本,它创建第二个参考相同的阵列。 (这适用于所有对象,而数组是一种对象。)所以你的循环,你到哪儿去后说:

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

...所有note3元素的引用相同的底层数组。

要做出实际拷贝,你可以将所有元素的跨使用循环手动复制,或者您可以使用.slice() method,使你的副本:

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

但是,这只能解决一半这个问题,因为note3base本身包含对其他数组的引用,并且.slice()只会复制这些引用。也就是说,尽管note3[0]note3[1](和2和3)将指代不同的阵列,但是note3[0][0]note3[1][0]note3[2][0]note3[3][0]将指代相同的["C", "E", "G"]阵列。 (等等)

你需要什么叫做“深层复制”。你可以嵌套循环做到这一点:

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

说了这么多,我觉得一个更简单的方法做这件事是不是有note3base引用数组变量,使之成为函数返回一个新的数组:

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"] 
    ]; 
} 

因为函数使用数组文本,将每次调用时创建数组的一个全新的阵列。所以,那么你就可以做到以下几点,而无需.slice()或嵌套的循环:

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

这是一个非常明确的解释!更好的解决方案来启动!非常感谢! –

3

TL; DR,这样做:

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

说明:

问题来自于在Javascrip中传递'通过值'和'引用'之间的区别PT。

当原始值分配给一个变量,像a = "string";,然后分配该另一个变量,像b = a;,该值被传递给b“由值”:其被分配给b,但b引用了内存的不同部分。内存中现在有两个“字符串”值,一个用于a,另一个用于b

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

这不是它对非基元类型如数组的作用方式。这里的值是通过引用传递给b,这意味着内存中仍然只有一个[1,2,3]数组,并且ab都指向它。这意味着你改变了a中的一个元素,它也会改变为b,因为它们在内存中引用相同的数组。所以,你得到这样的:

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

b[0]已经改变,因为它引用在内存中的相同位置a[0]。为了解决这个问题,我们需要在将它传递给另一个变量时明确地创建一个note3base的副本,而不是仅仅通过引用来传递它。我们可以用note3base.slice(0)来做到这一点。

编辑:阅读更多here