Для цикла в многомерном массиве 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