Converti ES6 Iterable in Array


100

Supponiamo che tu abbia un Javascript ES6 Iterable simile ad un array che sai in anticipo sarà di lunghezza finita, qual è il modo migliore per convertirlo in un array Javascript?

La ragione per farlo è che molte librerie js come underscore e lodash supportano solo gli array, quindi se desideri utilizzare una qualsiasi delle loro funzioni su un Iterable, devi prima convertirlo in un array.

In python puoi semplicemente usare la funzione list (). C'è un equivalente in ES6?


26
Array.from(iterable), vedi ECMA-262 ed 6 bozza .
RobG

Risposte:


156

È possibile utilizzare Array.from o l' operatore spread .

Esempio:

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 ]


2
Quasi lo stesso vale per let m = new Map()la struttura dati ES6 : per ottenere solo i valori della mappa, usa Array.fromo diffondi l'operatore m.values(), lo stesso per m.keys(). In caso contrario, si otterrà un array di array: [[key, value], [key, value]].
Nik Sumeiko

17

Sommario:

  • Array.from() funzione, richiede un iterabile come in input e restituisce un array dell'iterabile.
  • Operatore di diffusione: ...in combinazione con un array letterale.

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

Avvertenza durante la copia di array:

Sii consapevole del fatto che tramite questi metodi sopra viene creata solo una copia superficiale quando vogliamo copiare un array. Un esempio chiarirà il potenziale problema:

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

let newArr = [ ...arr ];

console.log(newArr);

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

console.log(newArr);

Qui, a causa dell'array annidato, il riferimento viene copiato e non viene creato alcun nuovo array. Pertanto, se mutiamo l'array annidato del vecchio array, questa modifica si rifletterà nel nuovo array (poiché si riferiscono allo stesso array, il riferimento è stato copiato).

Soluzione per avvertimento:

Possiamo risolvere il problema di avere copie superficiali creando un clone profondo dell'array usando JSON.parse(JSON.stringify(array)). Per esempio:

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)


12

È possibile utilizzare il metodo Array.from , che viene aggiunto in ES6, ma supporta solo array e oggetti iterabili come Maps e Sets (in arrivo anche in ES6). Per gli oggetti normali, puoi usare il metodo toArray di Underscore o il metodo toArray di lodash, poiché entrambe le librerie hanno effettivamente un ottimo supporto per gli oggetti, non solo per gli array. Se stai già utilizzando il carattere di sottolineatura o il lodash, fortunatamente possono gestire il problema per te, oltre ad aggiungere vari concetti funzionali come mappa e riduzione per i tuoi oggetti.


3

Il seguente approccio viene testato per 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}]

Non quello che è stato chiesto - vedi il modo in cui Array.from
João Antunes

0
 <<Your_Array>> = [].concat.apply([], Array.from( <<Your_IterableIterator>> ));

-4

Potresti anche fare:

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

O "nel modo più duro" utilizzando la funzione generatore ES5 + ( Fiddle funziona nell'attuale Firefox):

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

Entrambi gli approcci non sono certamente raccomandabili e sono solo una prova di concetto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.