Converter ES6 Iterable para Array

102

Digamos que você tenha um Iterable Javascript ES6 semelhante a um array que você sabe de antemão que terá comprimento finito. Qual é a melhor maneira de convertê-lo em um Array Javascript?

A razão para fazer isso é que muitas bibliotecas js, como sublinhado e lodash, suportam apenas Arrays, portanto, se você deseja usar qualquer uma de suas funções em um Iterable, primeiro ele deve ser convertido em um Array.

Em python, você pode apenas usar a função list (). Existe um equivalente no ES6?

Michael Bylstra
fonte
27
Array.from(iterable), consulte ECMA-262 ed 6 draft .
RobG

Respostas:

158

Você pode usar Array.from ou o operador spread .

Exemplo:

let x = new Set([ 1, 2, 3, 4 ]);

let y = Array.from(x);
console.log(y); // = [ 1, 2, 3, 4 ]

let z = [ ...x ];
console.log(z); // = [ 1, 2, 3, 4 ]

XåpplI'-I0llwlg'I -
fonte
2
Quase o mesmo se aplica à let m = new Map()estrutura de dados ES6 : para obter apenas os valores do Mapa, use Array.fromou espalhe o operador m.values(), mesmo para m.keys(). Caso contrário, você vai ter uma matriz de matrizes: [[key, value], [key, value]].
Nik Sumeiko
17

Resumo:

  • Array.from() função, ele pega um iterável como na entrada e retorna uma matriz do iterável.
  • Operador de propagação: ...em combinação com um literal de matriz.

const map = new Map([[ 1, 'one' ],[ 2, 'two' ]]);

const newArr1  = [ ...map  ];  // create an Array literal and use the spread syntax on it
const newArr2 = Array.from( map );  // 

console.log(newArr1, newArr2); 

Advertência ao copiar matrizes:

Esteja ciente do fato de que, por meio desses métodos acima, apenas uma cópia superficial é criada quando queremos copiar um array. Um exemplo irá esclarecer o problema potencial:

let arr = [1, 2, ['a', 'b']];

let newArr = [ ...arr ];

console.log(newArr);

arr[2][0] = 'change';

console.log(newArr);

Aqui, por causa do array aninhado, a referência é copiada e nenhum novo array é criado. Portanto, se alterarmos o array aninhado do array antigo, essa mudança será refletida no novo array (porque eles se referem ao mesmo array, a referência foi copiada).

Solução para advertência:

Podemos resolver o problema de ter cópias rasas criando um clone profundo do array usando JSON.parse(JSON.stringify(array)). Por exemplo:

let arr = [1, 2, ['a', 'b']]

let newArr = Array.from(arr);

let deepCloneArr = JSON.parse(JSON.stringify(arr));

arr[2][0] = 'change';

console.log(newArr, deepCloneArr)

Willem van der Veen
fonte
12

Você pode usar o método Array.from , que está sendo adicionado no ES6, mas só oferece suporte a arrays e objetos iteráveis ​​como Maps e Sets (também disponíveis no ES6). Para objetos regulares, você pode usar o método toArray de Underscore ou o método toArray de Lodash, uma vez que ambas as bibliotecas têm um grande suporte para objetos, não apenas arrays. Se você já está usando sublinhado ou lodash, então felizmente eles podem resolver o problema para você, além de adicionar vários conceitos funcionais como mapear e reduzir para seus objetos.

Colin Hartwig
fonte
3

A abordagem a seguir é testada para Maps:

const MyMap = new Map([
  ['a', 1],
  ['b', 2],
  ['c', 3]
]);

const MyArray = [...MyMap].map(item => {
  return {[item[0]]: item[1]}
});

console.info( MyArray ); //[{"a", 1}, {"b", 2}, {"c": 3}]
romano
fonte
Não foi o que foi perguntado - veja o Array.de caminho
João Antunes
0
 <<Your_Array>> = [].concat.apply([], Array.from( <<Your_IterableIterator>> ));
Dionis Oros
fonte
-3

Você também pode fazer:

let arr = [];
for (let elem of gen(...)){
    arr.push(elem);
}

Ou "da maneira mais difícil" usando a função do gerador ES5 + ( Fiddle funciona no Firefox atual):

var squares = function* (n) {
  for (var i = 0; i < n; i++) {
    yield i * i;
  }
};

var arr = [];
var gen = squares(10);
var g;
while (true) {
  g = gen.next();
  if (g.done) {
    break;
  }
  arr.push(g.value);
}

Ambas as abordagens certamente não são recomendáveis ​​e são apenas uma prova de conceito.

CodeManX
fonte