Crie uma matriz com o mesmo elemento repetido várias vezes


323

No Python, onde [2]está uma lista, o código a seguir fornece essa saída:

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

Existe uma maneira fácil de fazer isso com uma matriz em JavaScript?

Eu escrevi a seguinte função para fazê-lo, mas há algo mais curto ou melhor?

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


Respostas:


52

Você pode fazer assim:

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

Dobra a matriz em cada iteração, para criar uma matriz muito grande com poucas iterações.


Nota: Você também pode melhorar bastante sua função usando em pushvez de concat, pois concatcriará uma nova matriz a cada iteração. Assim (mostrado apenas como um exemplo de como você pode trabalhar com matrizes):

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

11
É muito mais eficiente alocar todas as entradas antecipadamente, arr = new Array(len);atribuir a elas pelo índice no loop, ou seja arr[i] = value;. Dessa forma, você paga apenas O (n) em vez de precisar realocar a matriz à medida que ela cresce. Em geral, é sempre melhor evitar o aumento de matrizes anexando quando possível. Se você souber o tamanho final, use-o.
Tom Karzes

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

1
@noobninja: ótima solução; você deve digitá-lo novamente como resposta para que possa ser votado.
jsalvata

693

Em ES6 usando matriz de enchimento () Método

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

3
O Internet Explorer e o Opera ainda não são compatíveis.
DenisKolodin

4
O Node.js <= 3 não suporta isso.
Li

1
@DenisKolodin O Opera atual faz. E Edge também. Veja compat-table
Janus Troelsen

4
@ Michael Você pode fazer isso com Array(5).fill([1,2,3]).flat(). Observe que flat () ainda é muito experimental e o suporte ao navegador é ruim.
Niko Ruotsalainen

3
Observe que o argumento to fillé avaliado uma vez; portanto, Array(9).fill(someMutable)cria nove referências someMutableno array (a mutação de uma mutará 'todas elas').
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
Pergunta boba, mas por que o novo Array (10) .map não funciona?
#


5
Com o ES6, isso pode ser "atualizado" para Array(...Array(10)).map(() => 5)o operador de spread ou também paraArray.from(Array(10)).map(() => 5)
Christophe Vidal

4
De acordo com a MDN , você pode fazer o seguinte:Array.from({length: 10}, () => 5);
Plusb Preco

2
@blazkovicz A matriz (10) cria uma matriz lenght = 10sem propriedades enumeráveis. .mapfunciona apenas em propriedades enumeráveis. O .applymétodo pega essa matriz e mapeia-a em um arguments array(um objeto semelhante a uma matriz) a ser passado para a Arrayfunção construtora. A matriz de argumentos não pode ser esparsa, portanto, as propriedades ausentes são definidas undefinede se tornam enumeráveis. Agora podemos usar .mapcomo pretendido
Cerved

91

podes tentar:

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

Atualização (01/06/2018) :

Agora você pode repetir um conjunto de caracteres.

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

Nota: Verifique mais sobre preenchimento (...) e de (...) para compatibilidade e suporte ao navegador.

Atualização (11/05/2019) :

Outra maneira, sem usar fillou from, que funciona para cadeias de caracteres de qualquer comprimento:

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

O mesmo que a resposta acima . Adicionando por uma questão de integridade.


1
Agradável. Mais curto e mais simples.
Johann Echavarria 27/10

2
+1 para manipulação simples. Uma pena que você não possa criar uma matriz de cadeias vazias com isso. Além de muito esperto ... #
28514 Quicker

1
A matriz (6) .join ('a'). Split ('a') fornece uma matriz de string vazia.
Vivek

17
Isso funciona apenas para 1 string de caracteres, portanto, não responde completamente à pergunta.
az_

3
@AlfonsoVergara: Em Javascript, String é um tipo primitivo (semântico de valor); não há como obter duas strings para referenciar os mesmos dados (porque strings não são referências em Javascript; são valores). Você precisa observar a semântica de referência com objetos e listas, mas não com seqüências de caracteres.
Quuxplusone

36

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

ou criar matriz com valor crescente

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


Bom, 👍 essa é a melhor abordagem se você precisar que o elemento seja dinâmico
#

Array.from({length:5}, i => 1)=> ié undefinedporque representa valor vazio Array.from({length:5}, (e, i)=>i)=> eé undefinedporque representa valor vazio. Deve ser Array.from({length:5}, v => 1)eArray.from({length:5}, (v, i)=>i)
Rafal Enden

33

No lodash não é tão ruim:

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

EDIT : Ainda melhor:

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

EDIT : Ainda melhor:

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

3
_.times (length, _.constant (value))
user1533401

1
dos documentos: _.fill (Matriz (3), 2); Que não está longe de ES6
kert

15

[c] * n pode ser escrito como:

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

então para [2] * 5

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

Na verdade, a matriz (6) .join (2) .split ('') seria mais fácil? Por que você precisaria do mapa?
Angela

4
que retorna ["2", "2", "2", "2", "2"], em vez de [2, 2, 2, 2, 2].
brook hong

10

Você também pode estender a funcionalidade do Array da seguinte maneira:

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 observar que estender a funcionalidade de objetos internos pode causar problemas se você estiver trabalhando com bibliotecas de terceiros. Sempre avalie isso em suas decisões.


Observe que, se você passar um objeto para fillcada índice da matriz, se referirá ao mesmo objeto, portanto, alterar um mudará todos eles. Isso não é muito difícil de resolver se se tornar um problema.
Shmiddty 19/09/12

Não entendo por que muitos usuários de javascript desconhecem o requisito de não protótipo de funções nativas.
brooNo

2
Um método de preenchimento foi adicionado no ES6. Portanto, eu não recomendaria adicionar suas próprias coisas ao protótipo, você substituirá a versão mais rápida e capaz.
Janus Troelsen

1
@JanusTroelsen Para evitar a substituição de bibliotecas javascript ou de terceiros, você pode verificar se existe antes de declará-lo. if (!Array.prototype.fill) { }
Oliver

1
@JanusTroelsen O que você quer dizer com "real polyfill" ?. Eu usei um polifyll. Quero dizer: verifique se há detecção e implementação de recursos, caso contrário.
Oliver


5

Caso você precise repetir uma matriz várias vezes:

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 resposta


em ES6, você pode fazer "abc" .repeat (3)
Janus Troelsen

4

Não há maneira mais fácil. Você precisa fazer um loop e inserir elementos na matriz.


Obrigado! Antes de aceitar, é pushmelhor ou concatmelhor, em termos de eficiência?
Curious2learn

O CONCAT precisa inspecionar duas matrizes, PUSH apenas adiciona outro elemento, então eu esperaria que PUSH fosse mais eficiente em geral, mas para os DADOS IDENTICOS, acho que a resposta de Guffa é a melhor.
Diodeus - James MacFarlane 19/09/12

Não há necessidade de loops, veja minha resposta.
Janus Troelsen

@JanusTroelsen, não é necessário fazer um loop, a menos que você queira uma maneira eficiente de executar esta ação. A sua é uma das mais lentas que você pode encontrar. push () para [] é o mais rápido.
chrilith

4

Use esta função:

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

Ou para uma versão mais compacta:

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

Ou para uma versão com capacidade para curry:

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

Você pode usar esta função com uma lista:

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

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

4

Se você precisar repetir uma matriz, use o seguinte.

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

retornará

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

ótimo oneliner usando uma matriz existente, o que eu precisava.
gneric

2

Outra linha:

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

1

Essa função cria uma matriz de elementos (comprimento) em que cada elemento é igual (valor) desde que (valor) seja um número inteiro ou sequência de caracteres de um número inteiro. Quaisquer números decimais serão truncados. Se você deseja números decimais, substitua "parseInt ( " por " 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;
}

Exemplos:

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

Eu tive problemas com os métodos mencionados quando uso uma matriz como

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

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

Para conseguir isso, estou 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;
};

Isso é legal, mas provavelmente deve ser nomeado cycle.
Drenmi

1

Eu descobri isso hoje enquanto tentava fazer uma matriz 2D sem usar loops. Em retrospecto, juntar uma nova matriz é legal; Tentei mapear uma nova matriz, que não funciona, pois o mapa ignora os slots vazios.

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

O caracter "#" pode ser qualquer caractere único válido. O 5 seria uma variável para o número de elementos que você deseja. O 7 seria o valor com o qual você deseja preencher sua matriz.

O novo método de preenchimento é melhor e, quando codifiquei isso, não sabia que ele existia, nem sabia que repetir é es6; Vou escrever um post sobre como usar esse truque em conjunto com reduzir para fazer coisas legais.

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


1

Tente isto:

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

1

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


0

Se você estiver usando um cinto de utilidade como lodash / underscore, poderá fazê-lo assim :)

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

0

Também pode ser usado como uma linha:

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

0

Melhorando a resposta de Vivek , isso funciona para cadeias de qualquer comprimento, para preencher uma matriz de comprimento n:Array(n+1).join('[string to be repeated][separator]').split('[separator]').slice(0, n)


-1

Eu precisava de uma maneira de repetir / repetir uma matriz (com n itens) m vezes.

Por exemplo, distribuindo uma lista (de pessoas) para uma semana / mês. Digamos que eu tenho 3 nomes e quero que eles repitam em uma 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"]
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.