2012-04-05 45 views
18

从现在开始,我使用这个循环遍历数组的元素,即使我在其中放入了具有各种属性的对象,也能正常工作。对于多维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[]; 

,并用两个阵列独立工作。这是更好的解决方案吗?

回答

36

你可以做这样的事情:

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 
+0

你的解决方案只适用于二维数组,但我发现了一种方法来循环通过任意数量的维数组:http://stackoverflow.com/a/15854485/975097 – 2013-07-20 22:15:12

+0

@AndersonGreen OP特别寻找二维数组,因此上面的答案。感谢您的链接 - 希望它可以帮助有人在未来寻找类似的解决方案! – 2013-07-20 23:57:05

+0

嗨,如何获得像'1,4,7','1,4,8','1,4,9','1,5,7','1,5,8'的结果...... – Bharadwaj 2013-08-01 11:26:09

1

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不应该被用于迭代一个数组,其中索引顺序 是重要的”

如果使用原来的语法,有不保证元素将按数字顺序访问。

12
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]); 
    } 
} 
+0

他问如何迭代它。 – 2012-04-05 02:26:22

+0

他问:“我可以用JavaScript做到这一点吗?” – binarious 2012-04-05 02:26:48

+0

您在我的评论后编辑了答案。你原来的帖子与迭代无关。 – 2012-04-05 02:29:10

6

试试这个:

var i, j; 

for (i = 0; i < cubes.length; i++) { 
    for (j = 0; j < cubes[i].length; j++) { 
     do whatever with cubes[i][j]; 
    } 
} 
+0

这将创建全局变量。 – 2012-04-05 02:26:37

+3

增加var i,j;公平地说,他没有说“不要创造全局变量”。 ;-) – 2012-04-05 02:29:35

3

一种高效地遍历数组是built-in array method .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) ; 
0

或者你也可以做到这一点或者用“的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 
2

如果您使用ES2015并且要定义自己的对象,像2-d数组迭代,你可以实现iterator protocol通过:

  1. 定义一个@@迭代函数调用Symbol.iterator返回...
  2. ...与next()函数返回对象...
  3. ...与一个或两个属性的对象:可选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'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} 
      } 
     }; 
    }; 
} 

现在,我们可以把我们的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); 
} 

创建我们自己的2-D迭代,而不是在我们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); 
    } 
} 

需要注意的是我们自定义的迭代在所有情况下都不会像二维阵列那样表现出来;例如,我们还没有实现一个map()函数。 This answer显示了如何实现一个生成器映射函数(see here用于迭代器和生成器之间的差异;同样,生成器是ES2016功能,而不是ES2015,因此如果使用babel编译,则需要change your babel presets)。