Depuis lors, j'utilise cette boucle pour parcourir les éléments d'un tableau, ce qui fonctionne bien même si je place des objets avec différentes propriétés à l'intérieur.
var cubes[];
for (i in cubes){
cubes[i].dimension
cubes[i].position_x
ecc..
}
Supposons maintenant que les cubes [] soient déclarés de cette façon
var cubes[][];
Puis-je le faire dans Javascript ? Comment puis-je alors automatiquement itérer dans
cubes[0][0]
cubes[0][1]
cubes[0][2]
cubes[1][0]
cubes[1][1]
cubes[1][2]
cubes[2][0]
ecc...
En guise de solution de contournement, je peux simplement déclarer:
var cubes[];
var cubes1[];
et travaillez séparément avec les deux tableaux. Est-ce une meilleure solution?
Vous pouvez faire quelque chose comme ça:
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 de travail:
La sortie de ce qui précède:
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
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]);
}
}
Une méthode efficace pour boucler sur un tableau est la méthode intégrée du tableau .map ()
Pour un tableau à 1 dimension, cela ressemblerait à ceci:
function HandleOneElement( Cuby ) {
Cuby.dimension
Cuby.position_x
...
}
cubes.map(HandleOneElement) ; // the map function will pass each element
pour un tableau à 2 dimensions:
cubes.map( function( cubeRow ) { cubeRow.map( HandleOneElement ) } )
pour un tableau à n dimensions de n'importe quelle forme:
Function.prototype.ArrayFunction = function(param) {
if (param instanceof Array) {
return param.map( Function.prototype.ArrayFunction, this ) ;
}
else return (this)(param) ;
}
HandleOneElement.ArrayFunction(cubes) ;
Essaye ça:
var i, j;
for (i = 0; i < cubes.length; i++) {
for (j = 0; j < cubes[i].length; j++) {
do whatever with cubes[i][j];
}
}
Si vous utilisez ES2015 et que vous souhaitez définir votre propre objet qui itère comme un tableau 2D, vous pouvez implémenter le protocole itérateur de:
Symbol.iterator
qui renvoie ...next()
qui renvoie ...value
optionnelle avec la valeur suivante (s'il en existe une) et une valeur booléenne done
qui est vraie si nous avons terminé l'itération.Une fonction d'itérateur de tableau unidimensionnelle ressemblerait à ceci:
// 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}
}
};
};
}
Maintenant, nous pouvons traiter notre objet Cubes
comme un itérable:
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);
}
Pour créer notre propre 2-D iterable, au lieu de retourner une valeur dans notre fonction next()
, nous pouvons retourner un autre 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}
}};
};
}
Maintenant, nous pouvons utiliser l'itération imbriquée:
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);
}
}
Notez que notre custom iterable ne se comportera pas comme un tableau 2D dans tous les cas. Par exemple, nous n'avons pas implémenté de fonction map()
. Cette réponse montre comment vous pouvez implémenter une fonction de carte de générateur ( voir ici pour la différence entre les itérateurs et les générateurs; de plus, les générateurs sont une fonctionnalité ES2016, pas ES2015, vous aurez donc besoin pour changer vos préréglages babel si vous compilez avec babel).
Un peu trop tard, mais cette solution est belle et soignée
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
}
}
Ou dans votre cas:
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
}
Remarque: La bouclefor ... of
est normalisée dans ES6. Ne l'utilisez donc que si vous avez un Complément Javascript ES5 (tel que Babel).
Autre remarque: Il existe des alternatives, mais elles présentent quelques différences et comportements subtils, tels que forEach()
, for...in
, for...of
et le for()
traditionnel. Cela dépend de votre cas pour décider lequel utiliser. (ES6 a également .map()
, .filter()
, .find()
, .reduce()
)
Ou vous pouvez le faire alternativement avec "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);
}
});
Si vous avez besoin de l'index d'un tableau, essayez ce 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++;
}
});
Et le résultat ressemblera à ceci:
[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
JavaScript n'a pas de telles déclarations. Ce serait:
var cubes = ...
indépendamment
Mais vous pouvez faire:
for(var i = 0; i < cubes.length; i++)
{
for(var j = 0; j < cubes[i].length; j++)
{
}
}
Notez que JavaScript autorise les tableaux déchiquetés, tels que:
[
[1, 2, 3],
[1, 2, 3, 4]
]
puisque les tableaux peuvent contenir n’importe quel type d’objet, y compris un tableau de longueur arbitraire.
Comme indiqué par MDC :
"for..in ne doit pas être utilisé pour parcourir un tableau où l'ordre d'index .__ est important"
Si vous utilisez votre syntaxe d'origine, rien ne garantit que les éléments seront visités dans l'ordre numérique.