Cree una matriz con el mismo elemento repetido varias veces

323

En Python, donde [2]hay una lista, el siguiente código proporciona esta salida:

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

¿Existe una manera fácil de hacer esto con una matriz en JavaScript?

Escribí la siguiente función para hacerlo, pero ¿hay algo más corto o mejor?

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
fuente
44
Posible duplicado: stackoverflow.com/questions/1295584/…
Larry Battle

Respuestas:

52

Puedes hacerlo así:

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

Duplica la matriz en cada iteración, por lo que puede crear una matriz realmente grande con pocas iteraciones.


Nota: También puede mejorar mucho su función utilizando en pushlugar de concat, ya concatque creará una nueva matriz en cada iteración. De esta manera (se muestra solo como un ejemplo de cómo puede trabajar con matrices):

function fillArray(value, len) {
  var arr = [];
  for (var i = 0; i < len; i++) {
    arr.push(value);
  }
  return arr;
}
Guffa
fuente
11
Es mucho más eficiente asignar todas las entradas por adelantado, arr = new Array(len);y luego asignarlas por índice en el ciclo, es decir arr[i] = value;. De esa forma solo paga O (n) en lugar de tener que seguir reasignando la matriz a medida que crece. En general, siempre es mejor evitar el crecimiento de matrices agregando cuando sea posible. Si conoce el tamaño final, úselo.
Tom Karzes
26
Array.from({length:5}).map(x => 2)
noobninja el
1
@noobninja: gran solución; debe volver a ingresarlo como respuesta para que se pueda votar.
jsalvata
693

En ES6 usando matriz de relleno () método

Array(5).fill(2)
//=> [2, 2, 2, 2, 2]
Niko Ruotsalainen
fuente
3
Internet Explorer y Opera aún no lo admiten.
DenisKolodin
44
Node.js <= 3 no es compatible con esto.
Junle Li
1
@DenisKolodin Current Opera lo hace. Y Edge también. Ver tabla de compatibilidad
Janus Troelsen
44
@ Michael Puedes hacerlo con Array(5).fill([1,2,3]).flat(). Tenga en cuenta que flat () todavía es muy experimental y el soporte del navegador es deficiente.
Niko Ruotsalainen
3
Tenga en cuenta que el argumento a fillse evalúa una vez, por lo que Array(9).fill(someMutable)crea nueve referencias a someMutableen la matriz (la mutación de una muta 'a todas').
Carl Smith el
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
fuente
66
Pregunta tonta, pero ¿por qué el nuevo Array (10) .map no funciona?
blazkovicz
1
blazkovicz, vea el comentario de zertosh sobre esta respuesta por la razón.
Ross Rogers
55
Con ES6, esto puede "actualizarse" Array(...Array(10)).map(() => 5)con el operador de propagación o también conArray.from(Array(10)).map(() => 5)
Christophe Vidal
44
De acuerdo con MDN , puede hacer esto:Array.from({length: 10}, () => 5);
Plusb Preco
2
@blazkovicz Array (10) crea una matriz lenght = 10sin propiedades enumerables. .mapsolo funciona en propiedades enumerables. El .applymétodo toma esta matriz y la asigna a un arguments array(un objeto similar a una matriz) para pasarla a la Arrayfunción de constructor. La matriz de argumentos no puede ser escasa, por lo que las propiedades que faltan se configuran undefinedy se vuelven enumerables. Ahora podemos usar .mapcomo se pretendía
CervEd
91

puedes probar:

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

Actualización (01/06/2018) :

Ahora puedes tener un conjunto de personajes que se repiten.

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

Nota: Consulte más información sobre el relleno (...) y de (...) para ver la compatibilidad y el soporte del navegador.

Actualización (05/11/2019) :

Otra forma, sin usar fillo from, que funciona para cadenas de cualquier longitud:

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

Igual que la respuesta anterior . Agregar por el bien de la integridad.

Vivek
fuente
1
Agradable. Más corto y más simple.
Johann Echavarria
2
+1 para un manejo sencillo. Una pena que no puedas crear una serie de cadenas vacías a partir de eso. Aparte de eso muy inteligente ...
rápido
1
Array (6) .join ('a'). Split ('a') me da una matriz de cadena vacía.
Vivek
17
Esto solo funciona para cadenas de 1 carácter, por lo que no responde la pregunta por completo.
az_
3
@AlfonsoVergara: en Javascript, String es un tipo primitivo (semántico de valor); no hay forma de obtener dos cadenas para hacer referencia a los mismos datos (porque las cadenas no son referencias en Javascript; son valores). Debe tener cuidado con la semántica de referencia con objetos y listas, pero no con cadenas.
Quuxplusone
36

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

o crear una matriz con un valor creciente

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

Thomson
fuente
Bien, este es el mejor enfoque si necesita el elemento dinámico
IliasT
Array.from({length:5}, i => 1)=> ies undefinedporque representa un valor vacío Array.from({length:5}, (e, i)=>i)=> ees undefinedporque representa un valor vacío. Debería ser Array.from({length:5}, v => 1)yArray.from({length:5}, (v, i)=>i)
Rafal Enden
33

En lodash no es tan malo:

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

EDITAR : Aún mejor:

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

EDITAR : Aún mejor:

_.fill(Array(5), 2);
Droogans
fuente
3
_.times (length, _.constant (value))
user1533401
1
de los documentos: _.fill (Array (3), 2); Que no está lejos de ES6
kert
15

[c] * n Se puede escribir como:

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

entonces para [2] * 5

Array(6).join(1).split('').map(function(){return 2;})
arroyo hong
fuente
En realidad, ¿no sería más fácil la matriz (6) .join (2) .split ('')? ¿Por qué necesitarías el mapa?
Angela
44
que devuelve ["2", "2", "2", "2", "2"], en lugar de [2, 2, 2, 2, 2].
Arroyo Hong
10

También puede ampliar la funcionalidad de Array de esta manera:

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] 

Debo señalar que ampliar la funcionalidad de los objetos integrados puede causar problemas si está trabajando con bibliotecas de terceros. Siempre pon esto en tus decisiones.

Shmiddty
fuente
Tenga en cuenta que si pasa un objeto en fillcada índice de la matriz, se referirá al mismo objeto, por lo que cambiar uno los cambiará a todos. Esto no es demasiado difícil de resolver si se convierte en un problema.
Shmiddty
No entiendo por qué muchos usuarios de JavaScript desconocen el requisito de no crear prototipos de funciones nativas.
brooNo
2
Se ha agregado un método de relleno en ES6. Por lo tanto, no recomendaría agregar sus propias cosas al prototipo, sobrescribirá la versión más rápida y más capaz.
Janus Troelsen
1
@JanusTroelsen Para evitar sobrescribir javascript o bibliotecas de terceros, puede verificar si existe antes de declararlo. if (!Array.prototype.fill) { }
Oliver
1
@JanusTroelsen ¿Qué quieres decir con "polyfill real"? Usé un polifyll. Quiero decir: verifique la detección e implementación de funciones en caso de que no sea así.
Oliver
5

En caso de que necesite repetir una matriz varias veces:

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

inspirado por esta respuesta

Henrik Christensen
fuente
en es6, puedes hacer "abc" .repeat (3)
Janus Troelsen
4

No hay manera más fácil. Necesita hacer un bucle e insertar elementos en la matriz.

Diodeus - James MacFarlane
fuente
¡Gracias! Antes de aceptar, ¿es pushmejor o concatmejor, en términos de eficiencia?
Curious2learn
CONCAT necesita inspeccionar dos matrices, PUSH simplemente agrega otro elemento, por lo que esperaría que PUSH sea más eficiente en general, pero para los DATOS IDÉNTICOS creo que la respuesta de Guffa lo logra.
Diodeus - James MacFarlane
No hay necesidad de bucles, mira mi respuesta.
Janus Troelsen
@JanusTroelsen, no es necesario realizar un bucle a menos que desee una forma eficiente de realizar esta acción. La tuya es una de las impedancias más lentas que puedes encontrar. push () a [] es el más rápido.
chrilith
4

Utiliza esta función:

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

O para una versión más compacta:

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

O para una versión con curry:

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

Puede usar esta función con una lista:

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

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

Si necesita repetir una matriz, use lo siguiente.

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

volverá

Array(9) [ "a", "b", "c", "a", "b", "c", "a", "b", "c" ]
etoxina
fuente
gran línea usando una matriz existente, lo que necesitaba.
Genérico
2

Otra frase:

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

Esta función crea una matriz de elementos (longitud) donde cada elemento es igual a (valor) siempre que (valor) sea un entero o una cadena de un entero. Cualquier número decimal será truncado. Si desea números decimales, reemplace "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;
}

Ejemplos:

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

Tuve problemas con los métodos mencionados cuando uso una matriz como

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

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

Para obtener esto estoy 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;
};
Xaver
fuente
Esto es bueno, pero probablemente debería nombrarse cycle.
Drenmi
1

Descubrí esto hoy mientras intentaba hacer una matriz 2D sin usar bucles. En retrospectiva, unirse a una nueva matriz es ordenado; Intenté mapear una nueva matriz, que no funciona ya que el mapa omite los espacios vacíos.

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

El carácter "#" puede ser cualquier carácter único válido. El 5 sería una variable para la cantidad de elementos que desea. El 7 sería el valor con el que desea llenar su matriz.

El nuevo método de relleno es mejor, y cuando codifiqué esto no sabía que existía, ni sabía que repetir es6; Voy a escribir una publicación de blog sobre el uso de este truco en conjunto con reduce para hacer cosas geniales.

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

Gordon Mágico
fuente
1

Prueba esto:

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

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

Amaldev ps
fuente
0

Si está utilizando un cinturón de utlidad como lodash / subrayado, puede hacerlo así :)

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

También se puede usar como una sola línea:

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

Mejorando la respuesta de Vivek , esto funciona para cadenas de cualquier longitud, para llenar una matriz de longitud n:Array(n+1).join('[string to be repeated][separator]').split('[separator]').slice(0, n)

Tigregalis
fuente
-1

Necesitaba una forma de repetir / repetir una matriz (con n elementos) m veces.

Por ejemplo, distribuir una lista (de personas) a una semana / mes. Digamos que tengo 3 nombres, y quiero que se repitan en una semana:

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
fuente