Estou procurando por alternativas ao abaixo para criar uma matriz JavaScript contendo de 1 a N, em que N é conhecido apenas em tempo de execução.
var foo = [];
for (var i = 1; i <= N; i++) {
foo.push(i);
}
Para mim, parece que deve haver uma maneira de fazer isso sem o loop.
javascript
arrays
Godders
fonte
fonte
1 ... N
?Respostas:
Se eu conseguir o que você procura, você deseja uma matriz de números
1..n
que você pode percorrer posteriormente.Se isso é tudo o que você precisa, você pode fazer isso?
quando você quiser usá-lo ... (não otimizado, apenas por exemplo)
por exemplo, se você não precisar armazenar nada no array, precisará apenas de um contêiner do comprimento certo para repetir ... isso pode ser mais fácil.
Veja em ação aqui: http://jsfiddle.net/3kcvm/
fonte
var n = 45;
e, em seguida, loop de1..n
faria.foo.length = M
--- As informações de corte são perdidas. Veja-o em ação ==> jsfiddle.net/ACMXpvar n = 45;
.new Array(45);
isso não "cria uma matriz de 45 elementos" (no mesmo significado que[undefined,undefined,..undefined]
faz). Em vez disso, "cria uma matriz vazia com comprimento = 45" ([undefined x 45]
), o mesmo quevar foo = []; foo.length=45;
. É por issoforEach
, emap
não se aplica neste caso.No ES6, usando os métodos Array from () e keys () .
Versão mais curta usando o operador spread .
fonte
map
a à matriz para ajustar os valores ([...Array(10).keys()].map(x => x++);
) para começar em 1map(x => x++)
paramap(x => ++x)
devido ao incremento de precedência acontece após o retorno valor :)map
quando você pode simplesmenteslice
?[...Array(N+1).keys()].slice(1)
keys
e apenas 1 mapa ->Array.from(Array(10)).map((e,i)=>i+1)
from
Array.from(Array(10), (e,i)=>i+1)
Você pode fazer isso:
ou com valores aleatórios:
Explicação
Primeiro, observe que
Number.call(undefined, N)
é equivalente aNumber(N)
, que apenas retornaN
. Nós usaremos esse fato mais tarde.Array.apply(null, [undefined, undefined, undefined])
é equivalente aArray(undefined, undefined, undefined)
, que produz uma matriz de três elementos e atribuiundefined
a cada elemento.Como você pode generalizar isso para N elementos? Considere como
Array()
funciona, que é mais ou menos assim:Desde o ECMAScript 5 ,
Function.prototype.apply(thisArg, argsArray)
também aceita um objeto semelhante a uma matriz do tipo pato como seu segundo parâmetro. Se invocarmosArray.apply(null, { length: N })
, ele executaráAgora temos uma matriz de elementos N , com cada elemento definido como
undefined
. Quando o chamamos.map(callback, thisArg)
, cada elemento será definido como o resultado decallback.call(thisArg, element, index, array)
. Portanto,[undefined, undefined, …, undefined].map(Number.call, Number)
mapearia cada elemento para(Number.call).call(Number, undefined, index, array)
, que é o mesmoNumber.call(undefined, index, array)
que, como observamos anteriormente, avalia comoindex
. Isso completa a matriz cujos elementos são iguais ao seu índice.Por que enfrentar o problema, em
Array.apply(null, {length: N})
vez de apenasArray(N)
? Afinal, ambas as expressões resultariam em uma matriz de elementos indefinidos no elemento N. A diferença é que, na expressão anterior, cada elemento é definido explicitamente como indefinido, enquanto no último, cada elemento nunca foi definido. De acordo com a documentação de.map()
:Portanto,
Array(N)
é insuficiente;Array(N).map(Number.call, Number)
resultaria em uma matriz não inicializada de comprimento N .Compatibilidade
Como essa técnica depende do comportamento
Function.prototype.apply()
especificado no ECMAScript 5, ela não funcionará em navegadores anteriores ao ECMAScript 5, como o Chrome 14 e o Internet Explorer 9.fonte
Function.prototype.call
o primeiro parâmetro é othis
objeto para mapear diretamente sobreArray.prototype.map
o parâmetro iterador tem um certo brilho.map
valores não atribuídos, na minha opinião. Outra versão (e possivelmente um pouco mais clara, embora mais longa) é:Array.apply(null, { length: N }).map(function(element, index) { return index; })
Array.apply(null, new Array(N)).map(function(_,i) { return i; })
ou, no caso das funções es6 e arrow, ainda mais curtos:Array.apply(null, new Array(N)).map((_,i) => i)
Várias maneiras de usar o ES6
Usando o operador spread (
...
) e o método de chavesPreenchimento / Mapa
Array.from
Array.from e
{ length: N }
hackNota sobre a forma generalizada
Todas as formas acima pode produzir matrizes inicializados para valores praticamente qualquer pretendidas mudando
i+1
a expressão necessário (por exemploi*2
,-i
,1+i*2
,i%2
e etc). Se a expressão puder ser expressa por alguma funçãof
, a primeira forma se tornará simplesmenteExemplos:
Como a matriz é inicializada
undefined
em cada posição, o valor dev
seráundefined
Exemplo mostrando todos os formulários
Mostrar snippet de código
Exemplo mais genérico com a função inicializadora personalizada,
f
isto é,ou ainda mais simples
Mostrar snippet de código
fonte
k++
, use++k
.Matrizes gerenciam in natura seus comprimentos. À medida que são percorridos, seus índices podem ser mantidos na memória e referenciados nesse ponto. Se um índice aleatório precisar ser conhecido, o
indexOf
método poderá ser usado.Dito isto, para suas necessidades, você pode apenas querer declarar uma matriz de um determinado tamanho:
ES6
Propagação
O uso do operador spread (
...
) e dokeys
método permite criar uma matriz temporária de tamanho N para produzir os índices e, em seguida, uma nova matriz que pode ser atribuída à sua variável:Preenchimento / Mapa
Você pode primeiro criar o tamanho da matriz de que precisa, preenchê-la com indefinida e criar uma nova matriz usando
map
, que define cada elemento para o índice.Array.from
Isso deve estar inicializando no tamanho N e preenchendo a matriz em uma passagem.
No lugar dos comentários e da confusão, se você realmente deseja capturar os valores de 1..N nos exemplos acima, existem algumas opções:
++i
).nos casos em que o índice não é usado - e possivelmente uma maneira mais eficiente - é criar sua matriz, mas fazer N representar N + 1 e, em seguida, sair da frente.
Então, se você deseja 100 números:
fonte
No ES6, você pode fazer:
Array(N).fill().map((e,i)=>i+1);
http://jsbin.com/molabiluwa/edit?js,console
Editar: alterado
Array(45)
paraArray(N)
desde que você atualizou a pergunta.fonte
.join.split
versão - mas eu ainda acho que o loop humilde é melhor.map
que em breve se tornará um padrão para coisas como esta.const gen = N => [...(function*(){let i=0;while(i<N)yield i++})()]
.fill()
é necessário. Vejo que é quando toco na repl do nó, mas desdeArray(1)[0] === undefined
que diferença faz a chamada para preencher ()Array(1).fill(undefined)
?Use o método Underscore _.range muito popular
fonte
Então chamado por
Não existe uma maneira integrada de fazer isso em Javascript, mas é uma função de utilitário perfeitamente válida para criar, se você precisar fazer isso mais de uma vez.
Edit: Na minha opinião, o seguinte é uma função de faixa melhor. Talvez apenas porque sou influenciado pelo LINQ, mas acho que é mais útil em mais casos. Sua milhagem pode variar.
fonte
Array
vez deArray.prototype
não haver motivo (pode até ser considerado um tanto estúpido) ter esse método em todas as matrizes.Array.range(1, 5)
provavelmente seria mais apropriado, mas há algo legal na escrita[].range(1, 5)
.foo = [1, 2, 3]; bar = foo.range(0, 10);
. Mas isso é apenas ... confuso.bar = Array.range(0, 10)
é muito mais claro e explícito. O intervalo não tem nada a ver com a instância, portanto não há razão para torná-lo um método de instância.a maneira mais rápida de preencher uma
Array
v8 é:O resultado será:
[0, 1, 2, 3, 4]
fonte
Esta pergunta tem muitas respostas complicadas, mas uma única linha:
Além disso, embora o texto acima seja curto (e arrumado) para escrever, acho que o seguinte é um pouco mais rápido (para um comprimento máximo de:
127, Int8,
255, Uint8,
32.767, Int16,
65.535, Uint16,
2.147.483.647, Int32,
4.294.967.295, Uint32.
(com base nos valores máximos de números inteiros ), veja também mais sobre matrizes digitadas ):
Embora essa solução também não seja tão ideal, ela cria duas matrizes e usa a declaração de variável extra "$" (não há nenhuma maneira de contornar isso usando esse método). Eu acho que a solução a seguir é a maneira mais rápida possível de fazer isso:
A qualquer momento após a declaração, você pode simplesmente usar a variável "arr" no escopo atual;
Se você deseja criar uma função simples (com algumas verificações básicas):
portanto, com a função acima, o super lento "single-liner" acima torna-se super-rápido e ainda mais curto:
fonte
fill
método:Array(255).fill(0,0,255)
Você pode usar isto:
por exemplo
criará a seguinte matriz:
fonte
new Array(10).join().split(',').map(function() {return ++arguments[1]});
?join
, umasplit
vez e uma vez para o que você realmente quer fazer) não é bom - eu sei que eles parecem ter caído em desuso por alguma razão, mas seria muito melhor simplesmente usar um bom loop antiquado !ES6, isso fará o truque:
confira o resultado:
fonte
[...Array(N + 1).keys()].slice(1)
vai render 1..N[...Array(N + 1).keys()]
esse código retorna uma matriz vazia, mas apenas no modo de produção, usando o modo de desenvolvimento funciona..keys()
resposta já foi dada anos atrás e tem mais de 500 votos. O que sua resposta adiciona a ela?Se você estiver usando o d3.js no seu aplicativo como eu, o D3 fornece uma função auxiliar que faz isso por você.
Portanto, para obter uma matriz de 0 a 4, é tão fácil quanto:
e para obter uma matriz de 1 a 5, conforme solicitado:
Confira este tutorial para mais informações.
fonte
Usando o operador de expansão ES2015 / ES6
fonte
i + 1
faria mais sentido do que++i
.Esta é provavelmente a maneira mais rápida de gerar uma matriz de números
Mais curto
Na linha
Se você deseja começar de 1
Quer uma função?
PORQUE?
while
é o loop mais rápidoA configuração direta é mais rápida que
push
[]
é mais rápido quenew Array(10)
é curto ... olha o primeiro código. então veja todas as outras funções aqui.
Se você gosta não pode viver sem por
ou
fonte
console.time()
para obter uma intuição, mas para uma prova, você precisa jsperf.com e mostra-lhe cross-browser resultados de outras pessoas (hardware diferentes, etc.)var a=[],b=N;while(b--){a[b]=a+1};
Se você estiver usando lodash, poderá usar _.range :
Exemplos:
fonte
a nova maneira de preencher
Array
é:O resultado será:
[0, 1, 2, 3, 4]
fonte
com o ES6, você pode fazer:
fonte
map
eforEach
funcionarão.Relatório Resumo Final. Drrruummm Rolll -
Este é o código mais curto para gerar uma matriz de tamanho N (aqui 10) sem usar o ES6 .A versão de Cocco acima é próxima, mas não a mais curta.
Mas o vencedor indiscutível deste código de golfe (competição para resolver um problema específico com o menor número de bytes de código-fonte) é Niko Ruotsalainen . Usando o Array Constructor e o operador de propagação ES6 . (A maioria da sintaxe do ES6 é typeScript válida, mas a seguir não é. Portanto, seja criterioso ao usá-lo)
fonte
a
. O circuito deve serfor(var a=[];n--;a[n]=n+1)
Existe uma outra maneira no ES6, usando Array.from, que recebe 2 argumentos, o primeiro é um arrayLike (neste caso, um objeto com
length
propriedade) e o segundo é uma função de mapeamento (nesse caso, mapeamos o item para seu índice)isso é mais curto e pode ser usado para outras seqüências, como gerar números pares
Além disso, ele tem um desempenho melhor do que a maioria das outras maneiras, porque faz um loop apenas uma vez na matriz. Verifique o snippit para algumas comparações
fonte
Array.from({length:N}, (v,i) => i+1)
Usando novos métodos Array e
=>
sintaxe da função do padrão ES6 (somente Firefox no momento da redação).Preenchendo orifícios com
undefined
:Array.from
transforma "buracos" emundefined
assimArray.map
funciona como esperado:fonte
Array.from({length: N}, (v, k) => k)
.Array.prototype.map.call
, por exemplo, para NodeLists retornadasdocument.querySelectorAll
. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…Array.from
que transforma os valores esparsos em indefinidos. Em vezArray(5)
é chamado como um objeto argumentos que por sua vez interpreta os valores esparsos como valores indefinidos :)fonte
[...Array(9)].map((_, i) => i)
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
fonte
No ES6:
ES5:
fonte
Apenas outra versão do ES6 .
Usando o
Array.from
segundo argumento opcional:Podemos construir a matriz numerada a partir das
Array(10)
posições vazias :fonte
[...Array(11).keys()].slice(1)
.Parece que o único sabor atualmente não nesta lista bastante completa de respostas é um que apresenta um gerador; para remediar isso:
que pode ser usado assim:
O bom disso é que você não precisa incrementar ... Para se inspirar na resposta que a igor-shubin deu, você pode criar uma variedade de randoms com muita facilidade:
E ao invés de algo
demoradooperacionalmente caro como:você poderia fazer:
fonte
Você pode usar o preenchimento da matriz e o mapa do Es6; assim como algumas pessoas sugeriram nas respostas que deram para esta pergunta. Abaixo estão alguns exemplos:
Prefiro isso porque acho mais direto e fácil.
fonte
Fonte: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from
fonte
Usando o ES6
fonte
Array.from(Array(n))
se o operador de propagação não for suportado.map
MDN : "Não é necessário elementos ausentes da matriz (ou seja, índices que nunca foram definidos, que foram foram excluídos ou aos quais nunca foi atribuído um valor) ".Object.keys(Array.apply(0, Array(3))).map(Number)
Retorna
[0, 1, 2]
. Muito semelhante à excelente resposta de Igor Shubin , mas com um pouco menos de truque (e um personagem a mais).Explicação:
Array(3) // [undefined × 3]
Gere uma matriz de comprimento n = 3. Infelizmente, essa matriz é quase inútil para nós, então temos que…Array.apply(0,Array(3)) // [undefined, undefined, undefined]
torne a matriz iterável. Nota: null é mais comum que o primeiro argumento da aplicação, mas 0 é menor.Object.keys(Array.apply(0,Array(3))) // ['0', '1', '2']
em seguida, obtenha as chaves da matriz (funciona porque Matrizes são o tipo de matriz é um objeto com índices para chaves.Object.keys(Array.apply(0,Array(3))).map(Number) // [0, 1, 2]
e mapeie as teclas, convertendo cadeias em números.fonte