JavaScript多维数组更新特定元素

7

我有一个字符串在js中被转换成了一个二维数组。

board = "...|.X.|...|"

它用于表示游戏棋盘。

每个.代表一个空格。

每个|代表一行。

每个X代表一堵墙。

EDIT: 下面是创建二维数组的代码

var src= "...|.X.|...|";
board = src.split(/\|/g);

for (var i = 0; i < board.length; i++) {
var cells = board[i].split('');
for (var j = 0; j < cells.length; j++) {
    cells[j] = parseInt(cells[j]);
}
board[i][j] = cells;
console.log(board[1][1])
//returns 'X'

                    

当我访问board [i] [j]时,它返回正确的结果:

[0] [0] = "."

[1] [1] = "X"

[1] [2] = "."

等等。

我想用表示一个棋子的字符串更新特定的元素。 然而,当我这样插入一个元素时:

board [0] [0] = "piece4"

该数组在firebug中返回如下:

board = "piece4 |. X。| ... |"

当它应该看起来像:

board =“。piece4 |. X。| ... |”

为什么[0] [1]和[0] [2]元素被覆盖?我是否没有正确理解js中的数组索引访问?


它们应该从(0,0)开始。 - sgowd
在你的示例代码中,我只看到了一维字符串。那些二维数组在哪里?如所示的代码-将一个字符串赋值给变量“board”,然后使用[0][0]访问它-根本不起作用(自然地返回未定义!)。 - Mörre
没有代码,就无法证明数组确实具有您认为的结构。因此,请同时包含数组/代码。 - Yoshi
你是如何从数组中获取字符串的呢? - Alex Turpin
如果你执行了 a = 1;,然后又执行了 a = 2,你不会期望 a 的值变成 3,那么在数组中为什么会有不同的期望呢? - T I
7个回答

75

我遇到了同样的问题,但是原因更为复杂。在这里,我想补充一下,以防有人搜索和我遇到的同样的问题:

我创建并填充了一个二维数组,如下所示:

var foo = Array(n).fill(Array(n).fill(0));

创建一个2维的n*n数组,并用0填充。

现在当我尝试像这样覆盖一个单元格时

foo[1][1] = 1;

我最终得到了以下数值:

[[0,1,0],
 [0,1,0],
 [0,1,0]]

依我看,这真的很令人惊讶。

原因是,只有一行被内部引用了三次。所以当我在“第二”行中改变了第一个索引时,它实际上改变了所有行。

底线:不要使用Array.fill创建多维数组!


12
真糟糕!fill() 看起来是创建一个二维零填充数组的完美方法,直到我遇到了完全相同的问题。 - Janosh
10
非常棒的语言表达。在我找到您的答案之前,我已经对这个问题怀疑了一个小时自己的理智。谢谢您,先生/女士! - informant09
1
当我创建多维数组时,也遇到了这个问题,但是我使用.push()方法创建了数组。如何在使用.push()方法创建多维数组时克服这个问题。 - user254153
@Lyes在下面的回答中解决了这个问题,创建了一个数组。https://dev59.com/KWLVa4cB1Zd3GeqPuT3J#64954317 - Quad Coders
1
你可以使用 let foo = JSON.parse(JSON.stringify(Array(n).fill(Array(n).fill(0)))); - Pefington
显示剩余3条评论

5

问题:

我猜您有一个一维数组,其中每个元素都是字符串。所以您的数组实际上看起来像这样:

array (
    [0] => '...',
    [1] => '.X.',
    [2] => '...'
)

当您需要以下内容时:

array (
    [0] => array (
        [0] => '.',
        [1] => '.',
        [2] => '.'
    ),
    [1] => array (
        [0] => '.',
        [1] => 'X',
        [2] => '.'
    ),
    [2] => array (
        [0] => '.',
        [1] => '.',
        [2] => '.'
    )
)

解决方案:

在构建二维数组时,确保明确声明board中的每个条目都是一个数组。因此,在构建时,您的代码可能如下所示:

board = new Array();
rows = 3;
for (var i = 0; i < rows; i++)
    board[i] = new Array('.', '.', '.');

谢谢,我相信这就是问题所在。我的字符串解析成2D数组的循环有误。 - Kirberry

1

我遇到了类似的问题。经过大量阅读后,这个方案最终符合我的需求。

myArr = [1,1,1];
var arr = new Array();

for (var i = 0; i < 10; i++) {
  arr[i] = Array.from(myArr);
}

//lets edit 3 positions
arr[0][1]= -1;
arr[3][2]= 100;
arr[8][0] = 8080;


for(var i=0; i<10; i++){
console.log(i + " === " + arr[i]);
}

输出:如果您注意到,只有编辑后的索引值发生了更改...其他内容没有变化。

0 === 1,-1,1  <---
1 === 1,1,1
2 === 1,1,1
3 === 1,1,100 <---
4 === 1,1,1
5 === 1,1,1
6 === 1,1,1
7 === 1,1,1
8 === 8080,1,1 <---
9 === 1,1,1

这是一个非常简单和完美的例子。现在我使用这种格式来避免在更新索引时出现重复! - Yo Apps

1

在JavaScript中创建二维数组的另一种方法是使用Array.from函数。

  var 2Darr =  Array.from(Array(5), () => {
                 return new Array(5).fill(0)
             })

这将创建一个完全填充0的5 x 5数组。 Array.from需要两个参数,第一个是javascript可迭代对象,用于提取数组,第二个是可选回调函数,我们可以在其中指定要应用于数组元素的内容。
像其他语言一样,可以简单地访问元素。

0
这里有一个函数,它可以更新二维数组中的特定元素,而不会改变原始数组(它返回一个新的二维数组):
const update2dArray = (arr, rowIndex, columnIndex, newValue) => {
  const nextArr = structuredClone(arr)
  if (!arr?.[rowIndex]?.[columnIndex]) {
    return nextArr
  }
  nextArr[rowIndex][columnIndex] = newValue
  return nextArr
}

0

这里有两点需要注意:

  1. 在每个维度中,数组都从索引0开始。
  2. 如果您将字符串作为2D数组访问,则每个元素都是char而不是字符串。

因此,如果您编写board [0] [0] ='X';,则会获得正确的行为(并且这会更改字符串的第一个字符,而不是第二个字符)。


0
上述情况和解决方案相当简单。在一组对象列表(通常称为数组,但那是另一个讨论话题)中更新特定值的问题具有更多实际和工业应用。你要面对的问题是认为查看特定单元格中的值,例如my_array [0] [0]返回“某个值”,也会通过赋值my_array [0] [0] ='新值'来改变该值。你会发现,根据你如何定义数组,更改将显示在同一行中的列中,而不是你需要的位置。 请参考示例代码,了解创建和管理多维对象列表(数组)的说明。
<html>
<head>
<title>JavaScript Object List/Array</title>
<script>
//Make a JavaScript array that can manage data of inventory between different locations over time.
var list_of_brands = ["BMW","Harley Davidson","Honda","Kawasaki"];
var list_of_locations = ["Dayton","Cincinnati"];

//a month of data
var DAYS_IN_A_MONTH = 30;
var calendar = [];
for(day_of_sales = 1; day_of_sales <= DAYS_IN_A_MONTH; day_of_sales++){

  //hold your locations
  var shop_location = [];//You need to create a new array for each day - that's part of the trick!

  for(location_index = 0;location_index < list_of_locations.length;location_index++){

  //set up some starting inventory
  var inventory = [];//You need to create a new array for each location - that's part of the trick!

      for(brand_index = 0; brand_index < list_of_brands.length; brand_index++){ 

        inventory[list_of_brands[brand_index]] = {"brand": list_of_brands[brand_index], "on_hand": 10,"sold": 0};

      };//end inventory loop

      shop_location[list_of_locations[location_index]] = {"city":list_of_locations[location_index],inventory};

  }//end location loop

  calendar[day_of_sales] = {"Day": day_of_sales, shop_location};

}//end calendar loop

//check your work
console.log('calendar:'); console.log(calendar);
console.log('shop_location:'); console.log(shop_location);
console.log('specific information: '); console.log(calendar[1].shop_location["Dayton"].inventory['BMW'].brand);//returns 'BMW'
console.log('change Dayton.BMW information: '); console.log(calendar[1].shop_location["Dayton"].inventory['BMW'].brand="Triumph");//change value
console.log('check work (Dayton.BMW): '); console.log(calendar[1].shop_location["Dayton"].inventory['BMW'].brand);//check work - PASS
console.log('check work (Cincinnati.BMW): '); console.log(calendar[1].shop_location["Cincinnati"].inventory["BMW"].brand);//check work other location - PASS!!

//Make some lasting and specific changes
console.log("Now make a change in the month's value over showing a sale on the 13th");
var sale_date = 13;
console.log("date of sale " + sale_date + "th");

var original_number_on_hand = calendar[sale_date].shop_location["Dayton"].inventory["BMW"].on_hand;
console.log("original_number_on_hand on that date: " + original_number_on_hand);

var number_of_units_sold = 3;
console.log("number_of_units_sold on that date: " + number_of_units_sold);

var new_inventory_level = original_number_on_hand - number_of_units_sold;
console.log("new_inventory_level: " + new_inventory_level);

for(date_index = sale_date; date_index  <= DAYS_IN_A_MONTH; date_index ++){  
  calendar[date_index].shop_location["Dayton"].inventory["BMW"].sold = number_of_units_sold;
  calendar[date_index].shop_location["Dayton"].inventory["BMW"].on_hand = new_inventory_level;
}

console.log("Show change in inventory");
  console.log(list_of_locations[0]+" has " + calendar[10].shop_location["Dayton"].inventory["BMW"].on_hand + " " + list_of_locations[1]+" has " + calendar[10].shop_location["Cincinnati"].inventory["BMW"].on_hand);
  console.log(list_of_locations[0]+" has " + calendar[11].shop_location["Dayton"].inventory["BMW"].on_hand + " " + list_of_locations[1]+" has " + calendar[11].shop_location["Cincinnati"].inventory["BMW"].on_hand);
  console.log(list_of_locations[0]+" has " + calendar[12].shop_location["Dayton"].inventory["BMW"].on_hand + " " + list_of_locations[1]+" has " + calendar[12].shop_location["Cincinnati"].inventory["BMW"].on_hand);
  console.log(list_of_locations[0]+" has " + calendar[13].shop_location["Dayton"].inventory["BMW"].on_hand + " " + list_of_locations[1]+" has " + calendar[13].shop_location["Cincinnati"].inventory["BMW"].on_hand);
  console.log(list_of_locations[0]+" has " + calendar[14].shop_location["Dayton"].inventory["BMW"].on_hand + " " + list_of_locations[1]+" has " + calendar[14].shop_location["Cincinnati"].inventory["BMW"].on_hand);
  console.log(list_of_locations[0]+" has " + calendar[15].shop_location["Dayton"].inventory["BMW"].on_hand + " " + list_of_locations[1]+" has " + calendar[15].shop_location["Cincinnati"].inventory["BMW"].on_hand);
  console.log(list_of_locations[0]+" has " + calendar[16].shop_location["Dayton"].inventory["BMW"].on_hand + " " + list_of_locations[1]+" has " + calendar[16].shop_location["Cincinnati"].inventory["BMW"].on_hand);

  //add new items to a shop's inventory
var inventory_2 =[];
for(brand_index = 0; brand_index < list_of_brands.length; brand_index++){ 

  inventory_2[list_of_brands[brand_index]] = {"brand": list_of_brands[brand_index], "on_hand": 10,"sold": 0};

};//end inventory loop
console.log("show inventory_2");console.log(inventory_2);
console.log("add inventory");inventory_2["Indian"] = {"brand": "Indian", "on_hand": 10,"sold": 0};
console.log("show updated inventory_2");console.log(inventory_2);

</script>
</head>
<body>
  <p>look in the JavaScript console for output</p>
</body>
</html>

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