Crea un array con lo stesso elemento ripetuto più volte


323

In Python, dove [2]è presente un elenco, il seguente codice fornisce questo output:

[2] * 5 # Outputs: [2,2,2,2,2]

Esiste un modo semplice per farlo con un array in JavaScript?

Ho scritto la seguente funzione per farlo, ma c'è qualcosa di più breve o migliore?

var repeatelem = function(elem, n){
    // returns an array with element elem repeated n times.
    var arr = [];

    for (var i = 0; i <= n; i++) {
        arr = arr.concat(elem);
    };

    return arr;
};


Risposte:


52

Puoi farlo in questo modo:

function fillArray(value, len) {
  if (len == 0) return [];
  var a = [value];
  while (a.length * 2 <= len) a = a.concat(a);
  if (a.length < len) a = a.concat(a.slice(0, len - a.length));
  return a;
}

Raddoppia l'array in ogni iterazione, quindi può creare un array davvero grande con poche iterazioni.


Nota: puoi anche migliorare molto la tua funzione usando pushinvece di concat, in quanto concatcreerà un nuovo array ogni iterazione. In questo modo (mostrato solo come esempio di come lavorare con le matrici):

function fillArray(value, len) {
  var arr = [];
  for (var i = 0; i < len; i++) {
    arr.push(value);
  }
  return arr;
}

11
È molto più efficiente allocare tutte le voci in anticipo, con arr = new Array(len);, quindi assegnarle a loro tramite indice nel ciclo, vale a dire arr[i] = value;. In questo modo paghi solo O (n) invece di dover continuare a riallocare l'array man mano che cresce. In generale, è sempre meglio evitare matrici crescenti aggiungendo quando possibile. Se conosci la dimensione finale, usala.
Tom Karzes,

26
Array.from({length:5}).map(x => 2)
Noobninja,

1
@noobninja: ottima soluzione; dovresti reinserirlo come risposta in modo che possa essere votato.
jsalvata,

693

In ES6 utilizzando il metodo fill () dell'array

Array(5).fill(2)
//=> [2, 2, 2, 2, 2]

3
Internet Explorer e Opera non lo supportano ancora.
DenisKolodin,

4
Node.js <= 3 non supporta questo.
Junle Li,

1
@DenisKolodin Current Opera lo fa. E anche Edge. Vedi tabella di compatibilità
Janus Troelsen,

4
@Michael Puoi farlo con Array(5).fill([1,2,3]).flat(). Si noti che flat () è ancora molto sperimentale e il supporto del browser è scadente.
Niko Ruotsalainen,

3
Si noti che l'argomento a fillviene valutato una volta, quindi Array(9).fill(someMutable)crea nove riferimenti a someMutablenell'array (mutando uno si trasforma 'tutti').
Carl Smith,

146
>>> Array.apply(null, Array(10)).map(function(){return 5})
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
>>> //Or in ES6
>>> [...Array(10)].map((_, i) => 5)
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5]

6
Domanda sciocca, ma perché il nuovo Array (10) .map non funziona?
blazkovicz,

1
blazkovicz, vedi il commento di zertosh su questa risposta per il motivo.
Ross Rogers,

5
Con ES6, questo può essere "aggiornato" Array(...Array(10)).map(() => 5)con l'operatore spread o anche conArray.from(Array(10)).map(() => 5)
Christophe Vidal,

4
Secondo MDN , puoi proprio così:Array.from({length: 10}, () => 5);
Plusb Preco

2
@blazkovicz Array (10) crea una matrice lenght = 10senza proprietà enumerabili. .mapfunziona solo su proprietà enumerabili. Il .applymetodo prende questo array e lo mappa in un arguments array(un oggetto simile a un array) da passare alla Arrayfunzione di costruzione. La matrice degli argomenti non può essere sparsa, quindi le proprietà mancanti vengono impostate undefinede diventano enumerabili. Ora possiamo usare .mapcome previsto
CervEd il

91

Puoi provare:

Array(6).join('a').split(''); // returns ['a','a','a','a','a'] (5 times)

Aggiornamento (01/06/2018) :

Ora puoi ripetere una serie di personaggi.

new Array(5).fill('a'); // give the same result as above;
// or
Array.from({ length: 5 }).fill('a')

Nota: controlla di più su fill (...) e da (...) per compatibilità e supporto del browser.

Aggiornamento (05/11/2019) :

Un altro modo, senza usare fillo from, che funziona con una stringa di qualsiasi lunghezza:

Array.apply(null, Array(3)).map(_ => 'abc') // ['abc', 'abc', 'abc']

Come sopra la risposta . Aggiungendo per completezza.


1
Bello. Più breve e più semplice.
Johann Echavarria,

2
+1 per una semplice gestione. Un peccato che non sia possibile creare una serie di stringhe vuote da questo. A parte quello molto intelligente ...
Più veloce il

1
Array (6) .join ('a'). Split ('a') mi dà array di stringhe vuote.
Vivek,

17
Funziona solo con 1 stringa di caratteri, quindi non risponde completamente alla domanda.
az_

3
@AlfonsoVergara: In Javascript, String è un tipo primitivo (valore-semantico); non c'è modo di ottenere due stringhe per fare riferimento agli stessi dati (perché le stringhe non sono riferimenti in Javascript; sono valori). Devi fare attenzione alla semantica di riferimento con oggetti ed elenchi, ma non con stringhe.
Quuxplusone,

36

Array.from({length:5}, i => 1) // [1, 1, 1, 1, 1]

o creare un array con valore crescente

Array.from({length:5}, (e, i)=>i) // [0, 1, 2, 3, 4]


Bene, 👍 questo è l'approccio migliore se hai bisogno dell'elemento dinamico
IliasT

Array.from({length:5}, i => 1)=> iè undefinedpoiché rappresenta un valore vuoto Array.from({length:5}, (e, i)=>i)=> eè undefinedpoiché rappresenta un valore vuoto. Dovrebbe essere Array.from({length:5}, v => 1)eArray.from({length:5}, (v, i)=>i)
Rafal Enden il

33

A lodash non è poi così male:

_.flatten(_.times(5, function () { return [2]; }));
// [2, 2, 2, 2, 2]

EDIT : Ancora meglio:

_.times(5, _.constant(2));
// [2, 2, 2, 2, 2]

EDIT : Ancora meglio:

_.fill(Array(5), 2);

3
_.times (lunghezza, _.costante (valore))
user1533401

1
dalla documentazione: _.fill (Array (3), 2); Che non è lontano da ES6
kert

15

[c] * n può essere scritto come:

Array(n+1).join(1).split('').map(function(){return c;})

così per [2] * 5

Array(6).join(1).split('').map(function(){return 2;})

In realtà, Array (6) .join (2) .split ('') non sarebbe più facile? Perché avresti bisogno della mappa?
Angela,

4
che restituisce ["2", "2", "2", "2", "2"], anziché [2, 2, 2, 2, 2].
Brook hong,

10

Puoi anche estendere le funzionalità di Array in questo modo:

Array.prototype.fill = function(val){
    for (var i = 0; i < this.length; i++){
        this[i] = val;
    }
    return this;
};
// used like:
var arry = new Array(5)​.fill(2);
// or
var arry = new Array(5);
arry.fill(2);


console.log(arry);​ //[2, 2, 2, 2, 2] 

Devo notare che l'estensione della funzionalità degli oggetti incorporati può causare problemi se si lavora con librerie di terze parti. Pesare sempre questo nelle tue decisioni.


Si noti che se si passa un oggetto in fillciascun indice dell'array si farà riferimento allo stesso oggetto, quindi cambiandone uno si cambieranno tutti. Questo non è troppo difficile da risolvere se diventa un problema.
Shmiddty,

Non capisco perché molti utenti javascript non siano consapevoli del requisito di non prototipare le funzioni native.
brooNo

2
Un metodo di riempimento è stato aggiunto in ES6. Quindi non consiglierei di aggiungere le tue cose al prototipo, sovrascriverai la versione più veloce e più capace.
Janus Troelsen,

1
@JanusTroelsen Per evitare di sovrascrivere librerie javascript o di terze parti è possibile verificare se esiste prima di dichiararlo. if (!Array.prototype.fill) { }
Oliver,

1
@JanusTroelsen Cosa intendi con "vero polyfill" ?. Ho usato una polifyll. Voglio dire: controlla il rilevamento e l'implementazione delle funzionalità nel caso non lo fosse.
Oliver,


5

Nel caso in cui sia necessario ripetere più volte un array :

var arrayA = ['a','b','c'];
var repeats = 3;
var arrayB = Array.apply(null, {length: repeats * arrayA.length})
        .map(function(e,i){return arrayA[i % arrayA.length]});
// result: arrayB = ['a','b','c','a','b','c','a','b','c']

ispirato da questa risposta


in es6, puoi fare "abc" .repeat (3)
Janus Troelsen,

4

Nessun modo più semplice. È necessario creare un ciclo e inserire elementi nell'array.


Grazie! Prima di accettare, è pushmeglio o concatmeglio, in termini di efficienza?
Curious2learn,

CONCAT deve ispezionare due array, PUSH aggiunge solo un altro elemento, quindi mi aspetto che PUSH sia più efficiente in generale, ma per i DATI IDENTICI penso che la risposta di Guffa lo inchioda.
Diodeus - James MacFarlane,

Non c'è bisogno di loop, vedi la mia risposta.
Janus Troelsen,

@JanusTroelsen, non è necessario eseguire il loop a meno che non si desideri un modo efficace per eseguire questa azione. La tua è una delle rallentazioni che puoi trovare. push () to [] è il più veloce.
chrilith,

4

Usa questa funzione:

function repeatElement(element, count) {
    return Array(count).fill(element)
}
>>> repeatElement('#', 5).join('')
"#####"

O per una versione più compatta:

const repeatElement = (element, count) =>
    Array(count).fill(element)
>>> repeatElement('#', 5).join('')
"#####"

O per una versione in grado di curry:

const repeatElement = element => count =>
    Array(count).fill(element)
>>> repeatElement('#')(5).join('')
"#####"

È possibile utilizzare questa funzione con un elenco:

const repeatElement = (element, count) =>
    Array(count).fill(element)

>>> ['a', 'b', ...repeatElement('c', 5)]
['a', 'b', 'c', 'c', 'c', 'c', 'c']

4

Se è necessario ripetere un array, utilizzare quanto segue.

Array.from({ length: 3 }).fill(['a','b','c']).flat()

sarà di ritorno

Array(9) [ "a", "b", "c", "a", "b", "c", "a", "b", "c" ]

ottimo oneliner usando un array esistente, quello di cui avevo bisogno.
gneric,

2

Un altro one-liner:

Array.prototype.map.call([]+Array(5+1),function(){ return '2'; })

1

Questa funzione crea una matrice di (lunghezza) elementi in cui ciascun elemento è uguale a (valore) purché (valore) sia un numero intero o una stringa di un numero intero. Eventuali numeri decimali verranno troncati. Se vuoi numeri decimali, sostituisci "parseInt ( " con " parseFloat ( "

function fillArray(length, intValue) {
     var vals = (new Array(length + 1)).join(intValue + '|').split('|').slice(0,length);
     for(var i = 0; i < length; i += 1) {
         vals[i] = parseInt(vals[i]);
     }
     return vals;
}

Esempi:

fillArray(5, 7) // returns [7,7,7,7,7]
fillArray(5, 7.5) // returns [7,7,7,7,7]
fillArray(5, 200) // returns [200,200,200,200,200]

1

Ho avuto problemi con i metodi citati quando utilizzo un array come

var array = ['foo', 'bar', 'foobar'];
var filled = array.fill(7);

//filled should be ['foo', 'bar', 'foobar', 'foo', 'bar', 'foobar', 'foo']

Per ottenere questo sto usando:

Array.prototype.fill = function(val){
    var l = this.length;
    if(l < val){
        for(var i = val-1-l; i >= 0; i--){
            this[i+l] = this[i % l];
        }
    }
    return this;
};

Questo è carino, ma probabilmente dovrebbe essere chiamato cycle.
Drenmi,

1

L'ho scoperto oggi mentre cercavo di creare un array 2D senza usare i loop. In retrospettiva, unire un nuovo array è pulito; Ho provato a mappare un nuovo array, che non funziona poiché la mappa salta slot vuoti.

"#".repeat(5).split('').map(x => 0)

Il carattere "#" può essere qualsiasi carattere singolo valido. Il 5 sarebbe una variabile per il numero di elementi desiderati. Il 7 sarebbe il valore che vuoi riempire il tuo array.

Il nuovo metodo di riempimento è migliore e quando l'ho codificato non sapevo che esistesse, né sapevo che la ripetizione è es6; Scriverò un post sul blog sull'uso di questo trucco in tandem con Riduci per fare cose interessanti.

http://jburger.us.to/2016/07/14/functionally-create-a-2d-array/


1

Prova questo:

"avinash ".repeat(5).trim().split(" ");


0

Se stai usando una cintura di utilità come lodash / underscore puoi farlo in questo modo :)

let result = _.map(_.times(foo), function() {return bar})

0

Può essere usato anche come un liner:

function repeat(arr, len) {
    while (arr.length < len) arr = arr.concat(arr.slice(0, len-arr.length));
    return arr;
}

0

Migliorando la risposta di Vivek , questo funziona con stringhe di qualsiasi lunghezza, per popolare una matrice di lunghezza n:Array(n+1).join('[string to be repeated][separator]').split('[separator]').slice(0, n)


-1

Avevo bisogno di un modo per ripetere / eseguire il loop di un array (con n elementi) m volte.

Ad esempio, distribuendo un elenco (di persone) a una settimana / mese. Diciamo che ho 3 nomi e che voglio ripetere tra una settimana:

fillArray(["Adam", "Blair", "Curtis"], 7); // returns ["Adam", "Blair", "Curtis", "Adam", "Blair", "Curtis", "Adam"]

function fillArray(pattern, count) {
    let result = [];
    if (["number", "string"].includes(typeof pattern)) {
        result = new Array(5);
        result.fill(pattern);
    }
    else if (pattern instanceof Array) {
        for (let i = 0; i < count; i++) {
            result = result.concat(pattern);
        }
        result = result.slice(0, count);
    }
    return result;
}

fillArray("a", 5);        // ["a", "a", "a", "a", "a"]
fillArray(1, 5);          // [1, 1, 1, 1, 1]
fillArray(["a", "b"], 5); // ["a", "b", "a", "b", "a"]
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.