Créer un tableau avec le même élément répété plusieurs fois

323

En Python, où se [2]trouve une liste, le code suivant donne cette sortie:

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

Existe-t-il un moyen simple de le faire avec un tableau en JavaScript?

J'ai écrit la fonction suivante pour le faire, mais y a-t-il quelque chose de plus court ou de meilleur?

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;
};
Curious2learn
la source

Réponses:

52

Vous pouvez le faire comme ceci:

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

Il double le tableau à chaque itération, de sorte qu'il peut créer un tableau vraiment grand avec peu d'itérations.


Remarque: Vous pouvez également améliorer considérablement votre fonction en utilisant pushau lieu de concat, comme concatcela créera un nouveau tableau à chaque itération. Comme ceci (montré juste comme un exemple de la façon dont vous pouvez travailler avec des tableaux):

function fillArray(value, len) {
  var arr = [];
  for (var i = 0; i < len; i++) {
    arr.push(value);
  }
  return arr;
}
Guffa
la source
11
Il est beaucoup plus efficace d'allouer toutes les entrées en amont, avec arr = new Array(len);, puis de les affecter par index dans la boucle, c'est-à-dire arr[i] = value;. De cette façon, vous ne payez que O (n) plutôt que de devoir réallouer le tableau à mesure qu'il grandit. En général, il est toujours préférable d'éviter de développer des tableaux en les ajoutant si possible. Si vous connaissez la taille finale, utilisez-la.
Tom Karzes
26
Array.from({length:5}).map(x => 2)
noobninja
1
@noobninja: excellente solution; vous devez le saisir à nouveau comme réponse afin qu'il puisse être voté.
jsalvata
693

En utilisant ES6 Matrice de remplissage () Méthode

Array(5).fill(2)
//=> [2, 2, 2, 2, 2]
Niko Ruotsalainen
la source
3
Internet Explorer et Opera ne le prennent pas encore en charge.
DenisKolodin
4
Node.js <= 3 ne prend pas en charge cela.
Junle Li
1
@DenisKolodin Current Opera le fait. Et Edge aussi. Voir compat-table
Janus Troelsen
4
@Michael Vous pouvez le faire avec Array(5).fill([1,2,3]).flat(). Notez que flat () est toujours très expérimental et le support du navigateur est médiocre.
Niko Ruotsalainen
3
Notez que l'argument to fillest évalué une fois, donc Array(9).fill(someMutable)crée neuf références à someMutabledans le tableau (une mutation mutant «toutes»).
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]
Janus Troelsen
la source
6
Question idiote, mais pourquoi le nouveau Array (10) .map ne fonctionne pas?
blazkovicz
1
blazkovicz, voir le commentaire de zertosh sur cette réponse pour la raison.
Ross Rogers
5
Avec ES6, cela peut être «mis à niveau» vers Array(...Array(10)).map(() => 5)avec l'opérateur de propagation ou aussi versArray.from(Array(10)).map(() => 5)
Christophe Vidal
4
Selon MDN , vous pouvez simplement aimer ceci:Array.from({length: 10}, () => 5);
Plusb Preco
2
@blazkovicz Array (10) crée un tableau lenght = 10sans propriétés énumérables. .mapne fonctionne que sur les propriétés énumérables. La .applyméthode prend ce tableau et le mappe dans un arguments array(un objet de type tableau) à transmettre à la Arrayfonction constructeur. Le tableau d'arguments ne peut pas être clairsemé, donc les propriétés manquantes sont définies sur undefinedet deviennent énumérables. Maintenant, nous pouvons utiliser .mapcomme prévu
CervEd
91

tu peux essayer:

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

Mise à jour (01/06/2018) :

Vous pouvez maintenant répéter un ensemble de caractères.

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

Remarque: Vérifiez plus sur fill (...) et from (...) pour la compatibilité et la prise en charge du navigateur.

Mise à jour (05/11/2019) :

Une autre façon, sans utiliser fillou from, qui fonctionne pour une chaîne de n'importe quelle longueur:

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

Identique à la réponse ci-dessus . Ajout par souci d'exhaustivité.

Vivek
la source
1
Agréable. Le plus court et le plus simple.
Johann Echavarria
2
+1 pour une manipulation simple. Dommage que vous ne puissiez pas créer un tableau de chaînes vides à partir de cela. A part ça, c'est très intelligent ...
Plus rapide
1
Array (6) .join ('a'). Split ('a') me donne un tableau de chaîne vide.
Vivek
17
Cela ne fonctionne que pour 1 chaîne de caractères, donc cela ne répond pas complètement à la question.
az_
3
@AlfonsoVergara: En Javascript, String est un type primitif (sémantique de valeur); il n'y a aucun moyen d'obtenir deux chaînes pour référencer les mêmes données (car les chaînes ne sont pas des références en Javascript; ce sont des valeurs). Vous devez faire attention à la sémantique de référence avec les objets et les listes, mais pas avec les chaînes.
Quuxplusone
36

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

ou créer un tableau avec une valeur croissante

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

Thomson
la source
Bien, c'est la meilleure approche si vous avez besoin de l'élément pour
dynamiser
Array.from({length:5}, i => 1)=> iest est undefinedcar il représente une valeur vide Array.from({length:5}, (e, i)=>i)=> eest undefinedcar il représente une valeur vide. Ça devrait être Array.from({length:5}, v => 1)etArray.from({length:5}, (v, i)=>i)
Rafal Enden
33

En lodash ce n'est pas si mal:

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

EDIT : Encore mieux:

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

EDIT : Encore mieux:

_.fill(Array(5), 2);
Droogans
la source
3
_.times (longueur, _.constant (valeur))
user1533401
1
à partir des documents: _.fill (Array (3), 2); Qui n'est pas loin de l'ES6
kert
15

[c] * n peut s'écrire:

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

donc pour [2] * 5

Array(6).join(1).split('').map(function(){return 2;})
ruisseau hong
la source
En fait, Array (6) .join (2) .split ('') ne serait-il pas plus facile? Pourquoi auriez-vous besoin de la carte?
Angela
4
qui renvoie ["2", "2", "2", "2", "2"], au lieu de [2, 2, 2, 2, 2].
brook hong
10

Vous pouvez également étendre les fonctionnalités d'Array comme suit:

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] 

Je dois noter que l'extension des fonctionnalités des objets intégrés peut provoquer des problèmes si vous travaillez avec des bibliothèques tierces. Considérez toujours cela dans vos décisions.

Shmiddty
la source
Notez que si vous passez un objet dans fillchaque index du tableau fera référence au même objet, donc en changer un les changera tous. Ce n'est pas trop difficile à résoudre si cela devient un problème.
Shmiddty du
Je ne comprends pas pourquoi de nombreux utilisateurs de javascript ignorent la nécessité de ne pas prototyper les fonctions natives.
brooNo
2
Une méthode de remplissage a été ajoutée dans ES6. Je ne recommanderais donc pas d'ajouter vos propres trucs au prototype, vous allez écraser la version plus rapide et plus performante.
Janus Troelsen
1
@JanusTroelsen Pour éviter d'écraser des bibliothèques javascript ou tierces, vous pouvez vérifier s'il existe avant de le déclarer. if (!Array.prototype.fill) { }
Oliver
1
@JanusTroelsen Qu'entendez-vous par "vrai polyfill"?. J'ai utilisé un polifyll. Je veux dire: vérifiez la détection et la mise en œuvre des fonctionnalités dans le cas contraire.
Oliver
5

Si vous devez répéter plusieurs fois un tableau :

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']

inspiré par cette réponse

Henrik Christensen
la source
dans es6, vous pouvez faire "abc" .repeat (3)
Janus Troelsen
4

Pas de moyen plus simple. Vous devez créer une boucle et pousser des éléments dans le tableau.

Diodée - James MacFarlane
la source
Merci! Avant d'accepter, c'est pushmieux ou concatmieux, en termes d'efficacité?
Curious2learn
CONCAT doit inspecter deux tableaux, PUSH ajoute juste un autre élément, donc je m'attendrais à ce que PUSH soit plus efficace en général, mais pour les DONNÉES IDENTIQUES je pense que la réponse de Guffa le résume.
Diodeus - James MacFarlane
Pas besoin de boucles, voir ma réponse.
Janus Troelsen
@JanusTroelsen, pas besoin de boucler sauf si vous voulez un moyen efficace de faire cette action. La vôtre est l'une des plus lentes à mettre en œuvre. push () to [] est le plus rapide.
chrilith
4

Utilisez cette fonction:

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

Ou pour une version plus compacte:

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

Ou pour une version curry:

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

Vous pouvez utiliser cette fonction avec une liste:

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

>>> ['a', 'b', ...repeatElement('c', 5)]
['a', 'b', 'c', 'c', 'c', 'c', 'c']
Ken Mueller
la source
4

Si vous devez répéter un tableau, utilisez ce qui suit.

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

reviendra

Array(9) [ "a", "b", "c", "a", "b", "c", "a", "b", "c" ]
étoxine
la source
grand oneliner utilisant un tableau existant, ce dont j'avais besoin.
gneric
2

Un autre doublure:

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

Cette fonction crée un tableau d'éléments (longueur) où chaque élément est égal à (valeur) tant que (valeur) est un entier ou une chaîne d'un entier. Tous les nombres décimaux seront tronqués. Si vous voulez des nombres décimaux, remplacez "parseInt ( " par " 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;
}

Exemples:

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]
TxRegex
la source
1

J'ai eu des problèmes avec les méthodes mentionnées lorsque j'utilise un tableau comme

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

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

Pour l'obtenir, j'utilise:

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;
};
Xaver
la source
C'est bien, mais devrait probablement être nommé cycle.
Drenmi
1

J'ai découvert cela aujourd'hui en essayant de créer un tableau 2D sans utiliser de boucles. Rétrospectivement, rejoindre un nouveau tableau est bien; J'ai essayé de mapper un nouveau tableau, ce qui ne fonctionne pas car la carte saute les emplacements vides.

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

Le caractère "#" peut être n'importe quel caractère unique valide. Le 5 serait une variable pour le nombre d'éléments que vous souhaitez. Le 7 serait la valeur avec laquelle vous souhaitez remplir votre tableau.

La nouvelle méthode de remplissage est meilleure, et lorsque j'ai codé cela, je ne savais pas qu'elle existait et je ne savais pas que répéter était es6; Je vais écrire un article de blog sur l'utilisation de cette astuce en tandem avec réduire pour faire des choses sympas.

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

Magical Gordon
la source
1

Essaye ça:

"avinash ".repeat(5).trim().split(" ");
Avinash
la source
1

var finalAry = [..."2".repeat(5).split("")].map(Number);
console.log(finalAry);

Amaldev ps
la source
0

Si vous utilisez une ceinture utlity comme lodash / underscore, vous pouvez le faire comme ceci :)

let result = _.map(_.times(foo), function() {return bar})
Shane Rogers
la source
0

Peut également être utilisé comme doublure:

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

Améliorant la réponse de Vivek , cela fonctionne pour des chaînes de n'importe quelle longueur, pour remplir un tableau de longueur n:Array(n+1).join('[string to be repeated][separator]').split('[separator]').slice(0, n)

Tigregalis
la source
-1

J'avais besoin d'un moyen de répéter / boucler un tableau (avec n éléments) m fois.

Par exemple, distribuer une liste (de personnes) à une semaine / mois. Disons que j'ai 3 noms, et je veux qu'ils répètent dans une semaine:

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"]
akinuri
la source