【问题标题】:Is it possible to iterate across nested arrays using for...of and/or for...in loop?是否可以使用 for...of 和/或 for...in 循环遍历嵌套数组?
【发布时间】:2019-04-13 02:31:55
【问题描述】:

假设我有一个由嵌套数组组成的“矩形网格”,如下所示:

let board = [
  ['a0', 'a1', 'a2', 'a3', 'a4'],
  ['b0', 'b1', 'b2', 'b3', 'b4'],
  ['c0', 'c1', 'c2', 'c3', 'c4'],
  ['d0', 'd1', 'd2', 'd3', 'd4'],
];

我正在尝试遍历其列,因此结果将类似于'a0', 'b0', 'c0', 'd0', 'a1'... etc

当然,我可以使用旧的 for 循环来做到这一点:

const iterateAcrossColumnsES5 = () => {
  for (let i = 0; i < board[0].length; i++) {
    for (let j = 0; j < board.length; j++) {
      console.log(board[j][i]);
    }
  }
}

但我喜欢尝试让它更像 ES6 一样简洁易读。我正在尝试使用 for.. of 和/或 for.. in 循环,但我只得到了:

const iterateAcrossColumnsES6 = () => {
  for (let [i, item] of Object.entries(board)) {
    for(let row of board) {
      console.log(row[i])
    }
  }
}

但它既不是 简洁 也不是 可读,而且它仅在 board 是“正方形”(父数组长度与其子项相同),否则我得到的迭代次数过多或不足。

有可能吗?我没有尝试使用map()forEach(),我很好。和他们一起,但我很好奇我是否只能使用for..offor..in

【问题讨论】:

  • ES6 不是 ES5 的替代品,如果标准 for 循环有意义,请使用标准 for 循环。
  • @Keith 我同意,我只是好奇这是否可能。
  • 您正在寻找 zip 函数 (stackoverflow.com/questions/4856717/…),然后是 firstCol = zip(...grid)[0]
  • 如果你只想控制台记录每个条目,那么 -> for (let i of board) { for (let j of i) console.log(j); }
  • @Keith 是的,我用它来迭代 rows ,但我需要迭代 columns

标签: javascript arrays loops ecmascript-6 iteration


【解决方案1】:

使用for...in

var board = [
  ['a0', 'a1', 'a2', 'a3', 'a4'],
  ['b0', 'b1', 'b2', 'b3', 'b4'],
  ['c0', 'c1', 'c2', 'c3', 'c4'],
  ['d0', 'd1', 'd2', 'd3', 'd4']
];

var result = [];

for (var i in board)
    for (var j in board[i])
        result[+j * board.length + +i] = board[i][j];
    
console.log(result);

不建议在数组上使用for...inMDN Docs for reference

使用for...of

var board = [
  ['a0', 'a1', 'a2', 'a3', 'a4'],
  ['b0', 'b1', 'b2', 'b3', 'b4'],
  ['c0', 'c1', 'c2', 'c3', 'c4'],
  ['d0', 'd1', 'd2', 'd3', 'd4']
];

var result = [], i=0,j=0;

for (var arr of board) {
    for (var val of arr)
        result[j++ * board.length + i] = val;
    i++;j=0;
}

console.log(result);

如果内部数组的长度不均匀,则数组中将出现空值。所以需要过滤那些。

【讨论】:

    【解决方案2】:

    您可以更改板子的iterator,然后使用数组传播或for...of 来获取项目:

    const board = [
      ['a0', 'a1', 'a2', 'a3', 'a4'],
      ['b0', 'b1', 'b2', 'b3', 'b4'],
      ['c0', 'c1', 'c2', 'c3', 'c4'],
      ['d0', 'd1', 'd2', 'd3', 'd4'],
    ];
    
    board[Symbol.iterator] = function() {
      const rows = board.length;
      const max = rows * board[0].length;
      let current = 0;
      return {
        next: () => ({
          value: this[current % rows][parseInt(current / rows)],
          done: current++ === max
        })
      };
    };
    
    console.log([...board]);
    
    for(const item of board) {
      console.log(item);
    }

    【讨论】:

      【解决方案3】:

      这只有在你有一块方板时才能达到你的目的。

      let board = [
        ["a0", "a1", "a2", "a3", "a4"],
        ["b0", "b1", "b2", "b3", "b4"],
        ["c0", "c1", "c2", "c3", "c4"],
        ["d0", "d1", "d2", "d3", "d4"],
        ["e0", "e1", "e2", "e3", "e4"]
      ];
      
      
      for (const i in board) {
        for (const j in board) {
          console.log(board[j][i]);
        }
      }

      【讨论】:

      • 看起来,合法,但我想遍历整个电路板,假设我不知道它的尺寸。
      • @edit:嗯,是的,但这些是,我需要
      • @HynekS 哎呀。午饭后我有点困。
      • @edit:没关系。如果棋盘是“正方形”(父母和孩子的长度相同),但如果不是则失败。
      【解决方案4】:

      你可以转置矩阵然后迭代。

      const transpose = (r, a) => a.map((v, i) => (r[i] || []).concat(v));
      let board = [['a0', 'a1', 'a2', 'a3', 'a4'], ['b0', 'b1', 'b2', 'b3', 'b4'], ['c0', 'c1', 'c2', 'c3', 'c4'],  ['d0', 'd1', 'd2', 'd3', 'd4']];
      
      for (let a of board.reduce(transpose, [])) {
          for (let v of a) {
              console.log(v);
          }
      }
      .as-console-wrapper { max-height: 100% !important; top: 0; }

      【讨论】:

      • 谢谢。不完全是我想要的(独角兽?),但非常有趣、鼓舞人心并且可能有用。
      【解决方案5】:

      在 js 中没有内置任何内容,但是通过两个小辅助函数,您可以以非常优雅的方式编写循环:

      function *chain(its) {
          for (let it of its)
              yield *it
      }
      
      function zip(arrays) {
          return arrays[0].map((e, i) => arrays.map(a => a[i]))
      }
      
      //
      
      let board = [
        ['a0', 'a1', 'a2', 'a3', 'a4'],
        ['b0', 'b1', 'b2', 'b3', 'b4'],
        ['c0', 'c1', 'c2', 'c3', 'c4'],
        ['d0', 'd1', 'd2', 'd3', 'd4'],
      ]
      
      
      console.log([...chain(board)].join(' '))
      
      
      console.log([...chain(zip(board))].join(' '))

      chain 连接多个可迭代对象,以便您可以将它们作为一个对象进行迭代,zip 获取一个数组数组并将其转置。

      【讨论】:

      • 看起来很有趣。我不得不承认,我不知道为什么 *it 会作为生成器产生,但我会看看 Kyle Simpsons 的“异步和性能”,并希望在那里找到答案……
      • 是否可以在列尾传递回调(console.log() 就够了)?
      • @HynekS:如果你需要为每一列做一些事情,使用没有链的 zip 并单独迭代它们可能会更容易,for(col of zip(board)) { for(item of col)...
      【解决方案6】:

      您可以使用map 创建a0,b0.... 的数组,然后进一步减少它。然后使用带有分隔符, 的连接来创建所需的结果

      let board = [
        ['a0', 'a1', 'a2', 'a3', 'a4'],
        ['b0', 'b1', 'b2', 'b3', 'b4'],
        ['c0', 'c1', 'c2', 'c3', 'c4'],
        ['d0', 'd1', 'd2', 'd3', 'd4'],
      ];
      
      
      
      var result = board.reduce((res, b) => res.map((elem, i) => elem + ',' + b[i])).join(',');
      console.log(result);

      【讨论】:

      • 目标是迭代项目,而不是打印逗号分隔的数组。
      猜你喜欢
      • 2021-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-14
      • 1970-01-01
      • 2021-04-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多