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


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

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]

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]

66
Pregunta tonta, pero ¿por qué el nuevo Array (10) .map no funciona?
blazkovicz


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.


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]


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

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

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.


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


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.


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

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

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

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]

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

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/


1

Prueba esto:

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


0

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

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

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

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)


-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"]
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.