Convertir ES6 Iterable a Array

100

Supongamos que tiene un Javascript ES6 Iterable similar a una matriz que sabe de antemano que tendrá una longitud finita, ¿cuál es la mejor manera de convertir eso en una matriz Javascript?

La razón para hacerlo es que muchas bibliotecas js, como el subrayado y lodash, solo admiten Arrays, por lo que si desea utilizar alguna de sus funciones en un Iterable, primero debe convertirlo en un Array.

En Python, puede usar la función list (). ¿Existe un equivalente en ES6?

Michael Bylstra
fuente
26
Array.from(iterable), ver ECMA-262 ed 6 borrador .
RobG

Respuestas:

156

Puede utilizar Array.from o el operador de propagación .

Ejemplo:

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 -
fuente
2
Casi lo mismo se aplica a let m = new Map()la estructura de datos de ES6 : para obtener solo los valores del mapa, use Array.fromo extienda el operador m.values(), lo mismo para m.keys(). De lo contrario, obtendrá una matriz de matrices: [[key, value], [key, value]].
Nik Sumeiko
17

Resumen:

  • Array.from() , toma un iterable como en input y devuelve una matriz del iterable.
  • Operador de propagación: ...en combinación con un 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); 

Advertencia al copiar matrices:

Tenga en cuenta el hecho de que a través de estos métodos anteriores solo se crea una copia superficial cuando queremos copiar una matriz. Un ejemplo aclarará el problema potencial:

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

let newArr = [ ...arr ];

console.log(newArr);

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

console.log(newArr);

Aquí, debido a la matriz anidada, la referencia se copia y no se crea una nueva matriz. Por lo tanto, si mutamos la matriz anidada de la matriz anterior, este cambio se reflejará en la nueva matriz (debido a que se refieren a la misma matriz, se copió la referencia).

Solución de advertencia:

Podemos resolver el problema de tener copias superficiales creando un clon profundo de la matriz usando JSON.parse(JSON.stringify(array)). Por ejemplo:

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
fuente
12

Puede usar el método Array.from , que se agrega en ES6, pero solo admite matrices y objetos iterables como Mapas y Conjuntos (que también vienen en ES6). Para objetos regulares, puede usar el método toArray de Underscore o el método toArray de lodash, ya que ambas bibliotecas tienen un gran soporte para objetos, no solo matrices. Si ya está utilizando subrayado o lodash, afortunadamente ellos pueden manejar el problema por usted, además de agregar varios conceptos funcionales como mapa y reducción para sus objetos.

Colin Hartwig
fuente
3

El siguiente enfoque se prueba 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
fuente
No es lo que se preguntó: vea la matriz. De camino
João Antunes
0
 <<Your_Array>> = [].concat.apply([], Array.from( <<Your_IterableIterator>> ));
Dionis Oros
fuente
-4

También puedes hacer:

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

O "por las malas" usando la función de generador ES5 + ( Fiddle funciona en el Firefox actual):

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

Sin embargo, ambos enfoques no son recomendables y son simplemente una prueba de concepto.

CodeManX
fuente