Можно ли выполнять итерацию по вложенным массивам, используя цикл for ... of и / или for ... in? - PullRequest
0 голосов
/ 09 ноября 2018

Допустим, у меня есть "прямоугольная сетка", состоящая из вложенных массивов, например:

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.

Конечно, я могу сделать это, используя старый добрый цикл:

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, более кратким и читабельным Я пытаюсь использовать для .. из и / или для .. в петлях, но я получил только до:

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

Но это ни кратко , ни читабельно , и это работает только в том случае, если board является квадратом (длина родительского массива равна так же, как его дети), в противном случае я получил слишком много или недостаточно итераций.

Можно это сделать? Я не пытался использовать map() или forEach(), я в порядке. с ними, но мне любопытно, могу ли я использовать только for..of или for..in.

Ответы [ 6 ]

0 голосов
/ 09 ноября 2018

Вы можете изменить итератор доски , а затем использовать массив или 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);
}
0 голосов
/ 09 ноября 2018

Использование 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...in для массивов. MDN Документы для справки

Использование 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);

Если внутренние массивы имеют неравномерную длину, в массиве будут присутствовать пустые значения. Так что надо их отфильтровать.

0 голосов
/ 09 ноября 2018

Ничего встроенного в 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 берет массив массивов и транспонирует его.

0 голосов
/ 09 ноября 2018

Вы можете использовать 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);
0 голосов
/ 09 ноября 2018

Вы можете транспонировать матрицу и затем выполнять итерацию.

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; }
0 голосов
/ 09 ноября 2018

Это будет служить вашим целям, только если у вас есть квадратная доска.

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]);
  }
}
...