Для цикла в многомерном массиве javascript
С тех пор я использую этот цикл для итерации по элементам массива, который отлично работает, даже если я помещаю объекты с различными свойствами внутри него.
var cubes[];
for (i in cubes){
cubes[i].dimension
cubes[i].position_x
ecc..
}
Теперь предположим, что кубы [] объявлены таким образом
var cubes[][];
Могу ли я сделать это в Javascript? Как я могу автоматически выполнять итерацию в
cubes[0][0]
cubes[0][1]
cubes[0][2]
cubes[1][0]
cubes[1][1]
cubes[1][2]
cubes[2][0]
ecc...
В качестве обходного пути я могу просто объявить:
var cubes[];
var cubes1[];
и работать отдельно с двумя массивами. Это лучшее решение?
Ответы
Ответ 1
Вы можете сделать что-то вроде этого:
var cubes = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
for(var i = 0; i < cubes.length; i++) {
var cube = cubes[i];
for(var j = 0; j < cube.length; j++) {
display("cube[" + i + "][" + j + "] = " + cube[j]);
}
}
Работа jsFiddle:
Результат выше:
cube[0][0] = 1
cube[0][1] = 2
cube[0][2] = 3
cube[1][0] = 4
cube[1][1] = 5
cube[1][2] = 6
cube[2][0] = 7
cube[2][1] = 8
cube[2][2] = 9
Ответ 2
var cubes = [["string", "string"], ["string", "string"]];
for(var i = 0; i < cubes.length; i++) {
for(var j = 0; j < cubes[i].length; j++) {
console.log(cubes[i][j]);
}
}
Ответ 3
Попробуйте следующее:
var i, j;
for (i = 0; i < cubes.length; i++) {
for (j = 0; j < cubes[i].length; j++) {
do whatever with cubes[i][j];
}
}
Ответ 4
Эффективным способом петли над массивом является встроенный метод массива .map()
Для 1-мерного массива это будет выглядеть так:
function HandleOneElement( Cuby ) {
Cuby.dimension
Cuby.position_x
...
}
cubes.map(HandleOneElement) ; // the map function will pass each element
для двумерного массива:
cubes.map( function( cubeRow ) { cubeRow.map( HandleOneElement ) } )
для n-мерного массива любой формы:
Function.prototype.ArrayFunction = function(param) {
if (param instanceof Array) {
return param.map( Function.prototype.ArrayFunction, this ) ;
}
else return (this)(param) ;
}
HandleOneElement.ArrayFunction(cubes) ;
Ответ 5
Если вы используете ES2015 и хотите определить свой собственный объект, который выполняет итерацию как двухмерный массив, вы можете реализовать протокол итератора by:
- Определение функции @@iterator, называемой
Symbol.iterator
, которая возвращает...
- ... объект с функцией
next()
, которая возвращает...
- ... объект с одним или двумя свойствами: необязательный
value
со следующим значением (если он есть) и логическим done
, который является истинным, если мы закончили итерацию.
Одномерная функция итератора массива будет выглядеть так:
// our custom Cubes object which implements the iterable protocol
function Cubes() {
this.cubes = [1, 2, 3, 4];
this.numVals = this.cubes.length;
// assign a function to the property Symbol.iterator
// which is a special property that the spread operator
// and for..of construct both search for
this[Symbol.iterator] = function () { // can't take args
var index = -1; // keep an internal count of our index
var self = this; // access vars/methods in object scope
// the @@iterator method must return an object
// with a "next()" property, which will be called
// implicitly to get the next value
return {
// next() must return an object with a "done"
// (and optionally also a "value") property
next: function() {
index++;
// if there still some values, return next one
if (index < self.numVals) {
return {
value: self.cubes[index],
done: false
};
}
// else there no more values left, so we're done
// IF YOU FORGET THIS YOU WILL LOOP FOREVER!
return {done: true}
}
};
};
}
Теперь мы можем рассматривать наш объект Cubes
как итеративный:
var cube = new Cubes(); // construct our cube object
// both call Symbol.iterator function implicitly:
console.log([...cube]); // spread operator
for (var value of cube) { // for..of construct
console.log(value);
}
Чтобы создать наш собственный двухмерный итеративный вариант вместо того, чтобы возвращать значение в нашей функции next()
, мы можем вернуть еще один итерабельный:
function Cubes() {
this.cubes = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
];
this.numRows = this.cubes.length;
this.numCols = this.cubes[0].length; // assumes all rows have same length
this[Symbol.iterator] = function () {
var row = -1;
var self = this;
// create a closure that returns an iterator
// on the captured row index
function createColIterator(currentRow) {
var col = -1;
var colIterator = {}
// column iterator implements iterable protocol
colIterator[Symbol.iterator] = function() {
return {next: function() {
col++;
if (col < self.numCols) {
// return raw value
return {
value: self.cubes[currentRow][col],
done: false
};
}
return {done: true};
}};
}
return colIterator;
}
return {next: function() {
row++;
if (row < self.numRows) {
// instead of a value, return another iterator
return {
value: createColIterator(row),
done: false
};
}
return {done: true}
}};
};
}
Теперь мы можем использовать вложенную итерацию:
var cube = new Cubes();
// spread operator returns list of iterators,
// each of which can be spread to get values
var rows = [...cube];
console.log([...rows[0]]);
console.log([...rows[1]]);
console.log([...rows[2]]);
// use map to apply spread operator to each iterable
console.log([...cube].map(function(iterator) {
return [...iterator];
}));
for (var row of cube) {
for (var value of row) {
console.log(value);
}
}
Обратите внимание, что наш пользовательский итерабель не будет вести себя как 2-мерный массив во всех случаях; например, мы не реализовали функцию map()
. Этот ответ показывает, как можно реализовать функцию отображения генератора (см. здесь для разница между итераторами и генераторами, а также генераторы - это функция ES2016, а не ES2015, поэтому вам нужно изменить свои пресетов babel, если вы компилируете с помощью babel).
Ответ 6
JavaScript не имеет таких объявлений. Это будет:
var cubes = ...
независимо
Но вы можете сделать:
for(var i = 0; i < cubes.length; i++)
{
for(var j = 0; j < cubes[i].length; j++)
{
}
}
Обратите внимание, что JavaScript разрешает массивы с зазубринами, например:
[
[1, 2, 3],
[1, 2, 3, 4]
]
поскольку массивы могут содержать любой тип объекта, включая массив произвольной длины.
Как отмечено MDC:
"for..in не следует использовать для итерации по массиву, где порядок индекса важно"
Если вы используете оригинальный синтаксис, нет никакой гарантии, что элементы будут посещаться в числовом порядке.
Ответ 7
Или вы можете сделать это в качестве альтернативы с помощью "forEach()":
var cubes = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
cubes.forEach(function each(item) {
if (Array.isArray(item)) {
// If is array, continue repeat loop
item.forEach(each);
} else {
console.log(item);
}
});
Если вам нужен индекс массива, попробуйте этот код:
var i = 0; j = 0;
cubes.forEach(function each(item) {
if (Array.isArray(item)) {
// If is array, continue repeat loop
item.forEach(each);
i++;
j = 0;
} else {
console.log("[" + i + "][" + j + "] = " + item);
j++;
}
});
И результат будет выглядеть так:
[0][0] = 1
[0][1] = 2
[0][2] = 3
[1][0] = 4
[1][1] = 5
[1][2] = 6
[2][0] = 7
[2][1] = 8
[2][2] = 9