从2D阵列生成3D阵列

时间:2016-06-14 08:27:30

标签: javascript multidimensional-array

我正在尝试创建一个音乐游戏,我必须从基本的2D阵列生成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,注[2] [1]为C Eb Gb,注[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;
}

2 个答案:

答案 0 :(得分:3)

TL; DR ,请执行以下操作:

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

<强>解释

问题来自于传递某些东西与价值之间的区别。和&#39;参考&#39;在Javascript。

将原始值分配给变量(例如a = "string";),然后将其分配给另一个变量(例如b = a;)时,该值将传递给b&#39; -value&#39;:已分配给b,但b引用了不同的内存部分。现在有两个&#34;字符串&#34;内存中的值,一个用于a,另一个用于b

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

这不适用于非基本类型,例如数组。这里的值通过引用传递给b&#39;这意味着内存中仍然只有一个[1,2,3]数组,a和{{ 1}}指着它。这意味着您更改了b中的元素,它也将更改为a,因为它们在内存中引用相同的数组。所以你明白了:

b

a = [1, 2, 3]; b = a; a[0] = "hello"; console.log(b); // ["hello", 2, 3] 已更改,因为它引用内存中与b[0]相同的位置。为了解决这个问题,我们需要在将note3base传递给另一个变量时明确地复制note3base,而不是仅仅通过引用传递它。我们可以使用a[0]执行此操作。

修改:了解更多here

答案 1 :(得分: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();
}