Reputation: 10554
Since now, I'm using this loop to iterate over the elements of an array, which works fine even if I put objects with various properties inside of it.
var cubes[];
for (i in cubes){
cubes[i].dimension
cubes[i].position_x
ecc..
}
Now, let's suppose cubes[] is declared this way
var cubes[][];
Can I do this in JavaScript? How can I then automatically iterate in
cubes[0][0]
cubes[0][1]
cubes[0][2]
cubes[1][0]
cubes[1][1]
cubes[1][2]
cubes[2][0]
ecc...
As a workaround, I can just declare:
var cubes[];
var cubes1[];
and work separately with the two arrays. Is this a better solution?
Upvotes: 54
Views: 250666
Reputation: 44275
forEach()
Based on icyrock.com's answer.
const cubes = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
cubes.forEach((n, i) => {
n.forEach((b, j) => {
console.log(`cubes[${i}][${j}] = ${b}`);
});
});
Upvotes: 1
Reputation: 832
A bit too late, but this solution is nice and neat
const arr = [[1,2,3],[4,5,6],[7,8,9,10]]
for (let i of arr) {
for (let j of i) {
console.log(j) //Should log numbers from 1 to 10
}
}
Or in your case:
const arr = [[1,2,3],[4,5,6],[7,8,9]]
for (let [d1, d2, d3] of arr) {
console.log(`${d1}, ${d2}, ${d3}`) //Should return numbers from 1 to 9
}
Note: for ... of
loop is standardised in ES6, so only use this if you have an ES5 Javascript Complier (such as Babel)
Another note: There are alternatives, but they have some subtle differences and behaviours, such as forEach()
, for...in
, for...of
and traditional for()
. It depends on your case to decide which one to use. (ES6 also has .map()
, .filter()
, .find()
, .reduce()
)
Upvotes: 19
Reputation: 3911
If you're using ES2015 and you want to define your own object that iterates like a 2-D array, you can implement the iterator protocol by:
Symbol.iterator
which returns...next()
function that returns...value
with the next value (if there is one) and a boolean done
which is true if we're done iterating.A one-dimensional array iterator function would look like this:
// 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's still some values, return next one
if (index < self.numVals) {
return {
value: self.cubes[index],
done: false
};
}
// else there's no more values left, so we're done
// IF YOU FORGET THIS YOU WILL LOOP FOREVER!
return {done: true}
}
};
};
}
Now, we can treat our Cubes
object like an iterable:
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);
}
To create our own 2-D iterable, instead of returning a value in our next()
function, we can return another iterable:
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}
}};
};
}
Now, we can use nested iteration:
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);
}
}
Note that our custom iterable won't behave like a 2-D array in all cases; for example, we haven't implemented a map()
function. This answer shows how you could implement a generator map function (see here for the difference between iterators and generators; also, generators are an ES2016 feature, not ES2015, so you'll need to change your babel presets if you're compiling with babel).
Upvotes: 2
Reputation: 670
Or you can do this alternatively with "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);
}
});
If you need array's index, please try this code:
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++;
}
});
And the result will look like this:
[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
Upvotes: 4
Reputation: 381
An efficient way to loop over an Array is the built-in array method .map()
For a 1-dimensional array it would look like this:
function HandleOneElement( Cuby ) {
Cuby.dimension
Cuby.position_x
...
}
cubes.map(HandleOneElement) ; // the map function will pass each element
for 2-dimensional array:
cubes.map( function( cubeRow ) { cubeRow.map( HandleOneElement ) } )
for an n-dimensional array of any form:
Function.prototype.ArrayFunction = function(param) {
if (param instanceof Array) {
return param.map( Function.prototype.ArrayFunction, this ) ;
}
else return (this)(param) ;
}
HandleOneElement.ArrayFunction(cubes) ;
Upvotes: 8
Reputation: 285077
JavaScript does not have such declarations. It would be:
var cubes = ...
regardless
But you can do:
for(var i = 0; i < cubes.length; i++)
{
for(var j = 0; j < cubes[i].length; j++)
{
}
}
Note that JavaScript allows jagged arrays, like:
[
[1, 2, 3],
[1, 2, 3, 4]
]
since arrays can contain any type of object, including an array of arbitrary length.
As noted by MDC:
"for..in should not be used to iterate over an Array where index order is important"
If you use your original syntax, there is no guarantee the elements will be visited in numeric order.
Upvotes: 1
Reputation: 4588
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]);
}
}
Upvotes: 24
Reputation: 28628
You can do something like this:
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]);
}
}
Working jsFiddle:
The output of the above:
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
Upvotes: 79
Reputation: 1183
Try this:
var i, j;
for (i = 0; i < cubes.length; i++) {
for (j = 0; j < cubes[i].length; j++) {
do whatever with cubes[i][j];
}
}
Upvotes: 5