在Javascript中声明一个空的二维数组?

118

我想在Javascript中创建一个二维数组,用于存储坐标(x,y)。由于这些坐标将由用户输入动态生成,因此我还不知道会有多少对坐标。

预定义的二维数组示例:

var Arr=[[1,2],[3,4],[5,6]];

我想我可以使用PUSH方法在数组末尾添加新记录。

如何声明一个空的二维数组,使得当我使用我的第一个Arr.push()时,它将被添加到索引0,并且每个下一个由push写入的记录都会取下一个索引?

这可能非常容易做到,我只是JS的新手,如果有人能写一段简短的可行代码片段供我查看,我将不胜感激。谢谢。


你尝试过 var Arr = new Array(new Array()); 吗?是的, pushpop 会在数组末尾添加或删除元素,而 shiftunshift 则会在数组开头删除或添加元素。 - abiessu
这听起来像是两个不同的问题。首先,您想要任意大小的数组。然后,您似乎在问一个涉及push方法的不同问题。(此外,如果您想回答自己的问题,我认为最好在答案部分中回答。)这是Google中创建JavaScript多维数组的排名前列的问题,我知道Google并不在这里决定内容,但我认为这是一个基本重要的问题,有各种奇怪的答案。 - PJ Brunet
23个回答

117
你可以像下面这样声明一个常规数组:

你可以像这样声明一个普通数组:

var arry = [];

那么当您有一对值要添加到数组中时,您所需要做的就是:

arry.push([value_1, value2]);

是的,第一次调用 arry.push 时,这对值将被放置在索引0处。

来自nodejs repl:

> var arry = [];
undefined
> arry.push([1,2]);
1
> arry
[ [ 1, 2 ] ]
> arry.push([2,3]);
2
> arry
[ [ 1, 2 ], [ 2, 3 ] ]

当然,由于JavaScript是动态类型语言,所以没有类型检查器强制执行数组保持二维。您必须确保仅添加坐标对,并避免执行以下操作:

> arry.push(100);
3
> arry
[ [ 1, 2 ],
  [ 2, 3 ],
  100 ]

1
这似乎是一个优雅的解决方案,因此我获得了X和Y坐标,并像这样插入它们:arry.push([x,y]); 但是,以后我该如何返回,例如索引0上的x坐标? - Zannix
2
你可以直接获取 arry[0][0]。(要获取 Y 坐标,可以获取 arry[0][1]。) - DJG

108

如果您想在创建时进行初始化,可以使用填充映射

const matrix = new Array(5).fill(0).map(() => new Array(4).fill(0));

5是行数,4是列数。


这在声明性上下文中也很有效,例如将2D数组预分配为对象成员。也许不是从头开始设计的东西,但对于像从其他语言移植这样的任务非常有用。 - steve.sims
41
请注意,这里使用 map(() => {}) 来创建一个独立的行是必要的。而使用 new Array(5).fill(new Array(4).fill(0)) 的方式非常危险。因为所有的行都填充有对同一个数组的引用,如果你更新了 arr[0][0] 的值,arr[1][0] 的值也会改变。当你将这个数组用作缓存表时,这可能会引发非常严重和黑暗的问题。 - Kaihua
2
@Kaihua 我是JavaScript的新手,但使用了Kamil Kiełczewski提供的打印格式代码,并且Abhinav的解决方案没有任何问题。如果修改任何元素,则不会对其他元素造成任何更改。我想你的评论类似于Python中的浅拷贝,但这里并非如此。 - yamex5
@Kaihua,我不明白,这个引用是如何指向同一个数组的。如果你创建了一个包含5个元素的数组(new Array(5)),并将其填充为新创建的数组(new Array(4))?!难道new Array()不意味着你正在创建一个新的数组吗?!JS到底怎么了?! - Rami Chasygov
2
@RamzanChasygov 根据上下文,编程语言可能存在不完美的情况 =D - Kaihua
1
@RamazanChasygov 代码乍一看可能有些反直觉,但它确实表现得像应该的那样。当您调用 Array(5).fill(new Array(4)) 时,将会发生以下情况:new Array(4) 将被调用一次,然后这个新创建的数组(长度为4)将被传递给 fill 函数。虽然只有一个对象在内存中被创建,但这个单个对象将用于填充所有数组元素,即所有数组元素指向内存中的同一位置。 - Benjamin M

72

ES6

具有3行和5列的矩阵m(删除.fill(0)以不使用零进行初始化)

[...Array(3)].map(_=>Array(5).fill(0))       

let Array2D = (r,c) => [...Array(r)].map(_=>Array(c).fill(0));

let m = Array2D(3,5);

m[1][0] = 2;  // second row, first column
m[2][4] = 8;  // last row, last column

// print formated array
console.log(JSON.stringify(m)
  .replace(/(\[\[)(.*)(\]\])/g,'[\n  [$2]\n]').replace(/],/g,'],\n  ')
);


@AndrewBenjamin - 问题具体在哪里?你能描述一下或提供测试案例吗? - Kamil Kiełczewski
我复制了你的代码,但是当我尝试随机访问数组中的值时,它会抛出错误。然而,只需进行微小的修改,它就可以正常工作:Array<number[]>(n + 1).fill(Array<number>(m+1).fill(0))。 - AndrewBenjamin
我想我知道出了什么问题,我在复制粘贴你的脚本后,不小心将第一个数组强制转换为<number>而不是<number[]>。所以这是我的错。 - AndrewBenjamin
1
关于fill方法,请注意:如果第一个参数是一个对象,则数组中的每个插槽都将引用该对象。因此,如果您这样做[...Array(r)].map(x=>Array(c).fill({ x: ..., y: ... })),则您将在矩阵的每一行中拥有相同的对象。 - Natalia Duran
1
@AkshayVijayJain 因为在空数组上,map 方法不会按我们预期的工作 - 但是对于这个问题的详细答案超出了 OP 的问题。请提出单独的问题或在 SO 上查找。 - Kamil Kiełczewski
显示剩余3条评论

37

如果您想这样访问矩阵:

matrix[i][j]

我觉得在循环中进行初始化是最方便的。

var matrix = [],
    cols = 3;

//init the grid matrix
for ( var i = 0; i < cols; i++ ) {
    matrix[i] = []; 
}

这将为您提供

[ [], [], [] ]

所以

matrix[0][0]
matrix[1][0]

返回undefined而不是错误信息"Uncaught TypeError: Cannot set property '0' of undefined"。


16

您可以使用简写语法将一个数组嵌套在另一个数组中:

   var twoDee = [[]];

7
您可以尝试这样做:-
var arr = new Array([]);

推送数据:

arr[0][0] = 'abc xyz';

13
arr[1][0]=3 => 未捕获的 TypeError: 无法设置未定义属性的 '0'。 - Kamil Kiełczewski

6
这个应该可以工作:
const arr = new Array(5).fill().map(_ => new Array(5).fill(0)) //

你可能会问,为什么我使用了map而不是:

const badArr = new Array(5).fill(new Array(5).fill(0)) //

上面例子的问题在于它添加了对传递到fill方法中的数组的引用:

enter image description here

虽然这个可以正常工作:

enter image description here


5

一句话总结

let m = 3 // rows
let n = 3 // columns
let array2D = Array(m).fill().map(entry => Array(n))

该实现为每个条目创建一个唯一的子数组。因此,设置 array2D[0][1] = 'm' 不会将每个条目的 [1] 索引设置为 'm'


1
让 array2D 等于 Array(3).fill().map(entry => Array(3)),就是这样。 - user4308987

4
你可以使用函数填充数组中的数组:

var arr = [];
var rows = 11;
var columns = 12;

fill2DimensionsArray(arr, rows, columns);

function fill2DimensionsArray(arr, rows, columns){
    for (var i = 0; i < rows; i++) {
        arr.push([0])
        for (var j = 0; j < columns; j++) {
            arr[i][j] = 0;
        }
    }
}

结果是:

Array(11)
0:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
1:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
2:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
3:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
4:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
5:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
6:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
7:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
8:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
9:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
10:(12)[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]


4
一个空数组是通过省略数值来定义的,像这样:
v=[[],[]]
a=[]
b=[1,2]
a.push(b)
b==a[0]

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