如何在JavaScript中创建二维数组?

1386

我在网上看到一些地方说JavaScript不能声明二维数组,有些则给出了一个例子并称可以,还有其他人驳斥这个例子等等。

  1. 如何在JavaScript中声明一个二维数组?(假设它是可能的)

  2. 如何访问它的成员?(myArray[0][1] 还是 myArray[0,1]?)


26
假设采用一种有些学究的定义,使用 JavaScript 技术实际上无法创建二维数组。但是,您可以创建一个数组的数组,这等同于同样的效果。 - I. J. Kennedy
22
FYI... 当你使用var arr2D = new Array(5).fill(new Array(3));将一个数组填充了更多的数组时,Array(5) 的每个元素都会指向同一个Array(3)。因此最好使用for循环动态地填充子数组。 - Josh Stribling
91
a = Array(5).fill(0).map(x => Array(10).fill(0)) - Longfei Wu
5
换句话说,fill 函数不会为要填充的数组的每个索引调用 new Array(3),因为它不是 Lambda 表达式或任何其他东西,比如 Longfei Wu 在上面的评论中,它最初使用 0 填充数组,然后使用 map 函数和 Lambda 来填充每个元素为新数组。fill 函数只是简单地根据你告诉它的内容来填充数组。这讲得通吗?有关 map 函数的更多信息,请参见:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/map - Josh Stribling
2
@kalehmann没问题:https://meta.stackoverflow.com/a/252017/2311074 如果新问题更好或有更好的答案,则将旧问题标记为新问题的重复。 - Adam
显示剩余7条评论
55个回答

1418

Practically? Yes. You can create an array of arrays which functions as an 2D array as every item is an array itself:

let items = [
  [1, 2],
  [3, 4],
  [5, 6]
];
console.log(items[0][0]); // 1
console.log(items[0][1]); // 2
console.log(items[1][0]); // 3
console.log(items[1][1]); // 4
console.log(items);

但从技术上讲,这只是一个数组的数组,而不是“真正”的二维数组,正如I. J. Kennedy指出的那样。

需要注意的是,您可以将数组嵌套到彼此中,从而创建“多维”数组。


44
用这种方式初始化一个大型多维数组将会很困难。然而,可以使用 这个函数 来创建一个空的多维数组,其中的维度作为参数指定。 - Anderson Green
5
@AndersonGreen,你提供了一个链接,对于那些对多维数组解决方案感兴趣的人来说这是一件好事,但问题和Ballsacian1的答案都是关于“2D”数组而不是“multi-D”数组。 - evilReiko
2
@SashikaXP,除了0之外的第一个索引都无法工作。 - Michael Franzl
2
问题是如何声明一个二维数组。这正是我所寻找的,我发现了这个问题和以下回答,它们未能区分声明和初始化之间的差异。还有已知长度或无界限的声明,但这两种情况都没有讨论到。 - chris
1
我认为这是一个“锯齿数组”(数组的数组)- JavaScript是否像其他一些语言那样区分“锯齿”和多维数组? - Luke T O'Brien
显示剩余3条评论

510
你只需将数组中的每个项变为一个数组。
var x = new Array(10);

for (var i = 0; i < x.length; i++) {
  x[i] = new Array(3);
}

console.log(x);


6
他们可以使用类似字符串的东西作为键和值吗?myArray['Book']['item1']? - Diego
46
@Diego,是的,但这不是数组的预期用途。当你的键是字符串时,最好使用对象。 - Matthew Crumley
10
我更喜欢这个例子胜过被采纳的答案,因为这个例子可以应用在动态大小的数组上,例如 new Array(size),其中 size 是一个变量。 - Variadicism
1
这个已经运行成功了,谢谢。你可以查看这个例子:Gargo https://jsfiddle.net/matasoy/oetw73sj/ - matasoy
代码运行良好;new Array(3)创建一个具有3个索引的新数组,并将每个索引初始化为undefined请参见'MDN中的'带有单个参数的数组构造函数' - mgthomas99
显示剩余2条评论

226

和activa的答案类似,这里有一个创建n维数组的函数:

function createArray(length) {
    var arr = new Array(length || 0),
        i = length;

    if (arguments.length > 1) {
        var args = Array.prototype.slice.call(arguments, 1);
        while(i--) arr[length-1 - i] = createArray.apply(this, args);
    }

    return arr;
}

createArray();     // [] or new Array()

createArray(2);    // new Array(2)

createArray(3, 2); // [new Array(2),
                   //  new Array(2),
                   //  new Array(2)]

2
这能创建一个四维数组吗? - trusktr
4
是的,你可以创建任意多个维度(在内存限制范围内)。只需传入四个维度的长度即可。例如:var array = createArray(2, 3, 4, 5); - Matthew Crumley
4
最佳答案!然而,我不建议使用0或1个参数(无用)。 - Apolo
2
@BritishDeveloper 是的。 这是一个每个长度为5的五维数组: [[[[[null,null],[null,null]],[[null,null],[null,null]]],[[[null,null],[null,null]],[[null,null],[null,null]]]],[[[[null,null],[null,null]],[[null,null],[null,null]]],[[[null,null],[null,null]],[[null,null],[null,null]]]]] - bb216b3acfd8f72cbc8f899d4d6963
5
@haykam 抱歉浪费你的时间 - 我是在用讽刺的方式表达 :/ - BritishDeveloper
显示剩余2条评论

216

如何创建一个空的二维数组(一行代码)

Array.from(Array(2), () => new Array(4))

第一维为2,第二维为4。

我们正在使用Array.from,它可以接受类数组参数和可选的映射函数。

Array.from(arrayLike[, mapFn[, thisArg]])

var arr = Array.from(Array(2), () => new Array(4));
arr[0][0] = 'foo';
console.info(arr);

相同的技巧可用于创建包含1...N的JavaScript数组


或者(但更低效 12%,n = 10,000

Array(2).fill(null).map(() => Array(4))

性能下降的原因是我们必须初始化第一维的值才能运行.map。请记住,Array 将不会分配位置,直到您通过.fill或直接值分配命令它为止。

var arr = Array(2).fill(null).map(() => Array(4));
arr[0][0] = 'foo';
console.info(arr);


跟进

这里有一个看起来正确但存在问题的方法。

 Array(2).fill(Array(4)); // BAD! Rows are copied by reference

虽然它确实返回了看似期望的二维数组 ([ [ <4 empty items> ], [ <4 empty items> ] ]),但有一个问题:第一维数组是按引用复制的。这意味着 arr[0][0] = 'foo' 实际上会改变两行而不是一行。

var arr = Array(2).fill(Array(4));
arr[0][0] = 'foo';
console.info(arr);
console.info(arr[0][0], arr[1][0]);


3
我建议这样写:Array.from({length:5}, () => []),意思是创建一个长度为5的空数组。 - vsync
1
这里很主观,但是这个答案(其中的第一和第二个)似乎是精炼、快速和现代化的最佳平衡。 - Brady Dowling
@zurfyx 有什么想法,或者有人知道为什么 WebStorm 抱怨这个问题吗?似乎 array.from 会将值保留为 undefined,然后我无法使用创建的数组,即使代码片段在 stackoverflow 上运行良好。 - FaultyJuggler
1
最佳一行代码回答! - Rodrigo Amaral
1
Array.from(Array(2), () => new Array(4))Array.from(Array(2), () => Array(4))有什么区别? - Owen Young
显示剩余3条评论

98

Javascript只有一维数组,但可以构建二维数组,正如其他人指出的那样。

以下函数可用于构建固定尺寸的二维数组:

function Create2DArray(rows) {
  var arr = [];

  for (var i=0;i<rows;i++) {
     arr[i] = [];
  }

  return arr;
}

列数并不重要,因为在使用数组之前不需要指定其大小。

然后你只需要调用:

var arr = Create2DArray(100);

arr[50][2] = 5;
arr[70][5] = 7454;
// ...

我想创建一个二维数组来表示一副牌。这个二维数组将保存牌的点数和花色。最简单的方法是什么? - Doug Hauf
1
function Create2DArray(rows) { var arr = []; for (var i=0;i<rows;i++) { arr[i] = []; } return arr; }function print(deck) { for(t=1;t<=4;t++) { for (i=1;i<=13;i++) { document.writeln(deck[t][i]); } } }function fillDeck(d) { for(t=1;t<=4;t++) { myCardDeck[t][1] = t; for (i=1;i<=13;i++) { myCardDeck[t][i] = i; } } }function loadCardDeck() { var myCardDeck = Create2DArray(13); fillDeck(myCardDeck); print(myCardDeck); } - Doug Hauf
2
@Doug:实际上,您想要一个具有2个属性的对象的一维数组。var deck= []; deck[0]= { face:1, suit:'H'}; - TeasingDart
@DougHauf 那是一个被压缩的二维数组吗?? :P :D - Mahi

86

最简单的方法:

var myArray = [[]];

31
这是一个二维数组。 - Maurizio In denmark
17
注意一下,对myArray[0][whatever]进行赋值是可以的,但是尝试设置myArray[1][whatever]会提示myArray[1]未定义。 - Philip
25
在将myArray[1][0]赋值为5之前,您需要先设置myArray[1]=[];。请注意,不要改变原来的意思。 - 182764125216
7
请注意,这并不会像@AndersonGreen所说的那样“创建一个空的1x1数组”。它创建了一个“1x0”数组(即包含0列的数组中包含1行)。myArray.length == 1myArray[0].length == 0。如果你将一个“真正空的”“0x0”数组复制到其中,就会得到错误的结果。 - JonBrave
4
@182764125216 这对我来说是今天的知识收获,谢谢 :) - th3pirat3
显示剩余3条评论

47

一些人认为不可能是因为二维数组实际上只是一个数组的数组。这里提供的其他评论都提供了在JavaScript中创建二维数组的完全有效的方法,但最纯粹的观点是您有一个对象的一维数组,每个对象都是由两个元素组成的一维数组。

因此,这就是产生冲突的观点的原因。


43
不是。在一些语言中,你可以有多维数组,比如string[3,5] = "foo";。对于某些情况来说,这是一种更好的方法,因为Y轴实际上不是X轴的子集。 - rafasoares
4
一旦转化为底层机器码,所有维度大于1的张量都是数组的数组,不论我们使用的是哪种语言。出于缓存优化的原因,值得牢记这一点。任何严肃面向数值计算的好的编程语言都将允许你调整内存中的多维结构,使你最常使用的维度被连续地存储。Python的Numpy、Fortran和C就是其中之一。事实上,有些情况下,为了这个原因而将维度降低成多个结构是值得的。 - Thomas Browne
计算机没有维度的概念。只有一个维度,即内存地址。其他所有东西都是为了程序员的方便而进行的符号装饰。 - TeasingDart
3
@ThomasBrowne 不完全正确。"数组的数组"需要一些存储空间来存储内部数组的大小(它们可能不同),并且还需要另一个指针解引用,以找到存储内部数组的位置。在任何“体面”的编程语言中,多维数组与交错数组不同,因为它们本质上是不同的数据结构。(令人困惑的是,虽然C数组使用[a][b]语法进行索引,但它们是多维数组。) - polkovnikov.ph

39

很少有人展示使用push的方法:
为了带来新的东西,我将向您展示如何使用某些值初始化矩阵,例如:0或空字符串“”。
提醒一下,如果您有一个10个元素的数组,在JavaScript中,最后一个索引将是9!

function matrix( rows, cols, defaultValue){

  var arr = [];

  // Creates all lines:
  for(var i=0; i < rows; i++){

      // Creates an empty line
      arr.push([]);

      // Adds cols to the empty line:
      arr[i].push( new Array(cols));

      for(var j=0; j < cols; j++){
        // Initializes:
        arr[i][j] = defaultValue;
      }
  }

return arr;
}

使用示例:

x = matrix( 2 , 3,''); // 2 lines, 3 cols filled with empty string
y = matrix( 10, 5, 0);// 10 lines, 5 cols filled with 0

我从你的程序中删除了最后一个 for(它设置默认值),并写下了 m=matrix(3,4); m[1][2]=2; console.log(JSON.stringify(m)); - 我们得到了一个非常奇怪的矩阵(嵌套太多)- 你在最后一个 for-defaultValue 步骤中修复了它,但我认为你可以重写程序,在设置默认值之前使用更少的嵌套数组。 - Kamil Kiełczewski
1
对于 JavaScript 领域来说,这是完美的解决方案。非常感谢您提供这个解决方案。 - AMIC MING
You are so kind AMIC - Sergio Abreu

30

两行诗:

var a = []; 
while(a.push([]) < 10);

它将生成长度为10的数组a,其中填充有数组。 (push会向数组添加元素并返回新的长度)


14
这个一句话代码的意思是:创建一个空数组a,然后将10个空的子数组push到a中。 - Bergi
@Bergi,下一行代码中变量仍然会被定义吗? - StinkyCat
1
@StinkyCat:是的,这就是var的工作原理。它始终是函数作用域。 - Bergi
@StinkyCat 它是函数作用域,而不是块级作用域。因此,在循环之后(直到父函数的结尾),变量a仍将可用。 - domenukk
1
domenukk 和 @Bergi,你们两个都是正确的。我试过了,在 for 循环后我可以访问 a。对不起!谢谢你们,这给了我一个教训 ;) - StinkyCat
显示剩余2条评论

28
最理智的答案似乎是:

var nrows = ~~(Math.random() * 10);
var ncols = ~~(Math.random() * 10);
console.log(`rows:${nrows}`);
console.log(`cols:${ncols}`);
var matrix = new Array(nrows).fill(0).map(row => new Array(ncols).fill(0));
console.log(matrix);

请注意,我们无法直接使用行进行填充,因为填充使用的是浅拷贝构造函数,因此所有行都将共享相同的内存...以下示例演示了每行如何共享(取自其他答案):
// DON'T do this: each row in arr, is shared
var arr = Array(2).fill(Array(4));
arr[0][0] = 'foo'; // also modifies arr[1][0]
console.info(arr);

这应该在最顶部。我之前使用过 Array.apply(null, Array(nrows)) 做了类似的事情,但这个更加优雅。 - dimiguel
关于我的最后一条评论... Internet Explorer 和 Opera 不支持 fill。这在大多数浏览器上都无法工作。 - dimiguel
@dimgl 在这种情况下,可以使用常量映射来模拟FillArray(nrows).map(() => 0)Array(nrows).map(function(){ return 0; }); - Conor O'Brien

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接