Digamos que eu tenho uma matriz Javascript parecida com a seguinte:
["Element 1","Element 2","Element 3",...]; // with close to a hundred elements.
Que abordagem seria apropriada para dividir (dividir) a matriz em muitas matrizes menores com, digamos, 10 elementos no máximo?
javascript
arrays
split
Industrial
fonte
fonte
const chunk = (arr, n) => arr.length ? [arr.slice(0, n), ...chunk(arr.slice(n), n)] : []
que é bom e curto, mas parece demorar cerca de 256 × enquanto a resposta do @ AymKdn para 1.000 elementos e 1.058 × para 10.000 elementos!Respostas:
O método array.slice pode extrair uma fatia do início, meio ou fim de uma matriz para qualquer finalidade que você precisar, sem alterar a matriz original.
fonte
chunk
ser0
. (loop infinito)const array_chunks = (array, chunk_size) => Array(Math.ceil(array.length / chunk_size)).fill().map((_, index) => index * chunk_size).map(begin => array.slice(begin, begin + chunk_size));
.Modificado de uma resposta por dbaseman: https://stackoverflow.com/a/10456344/711085
adenda menor :
Devo salientar que o exposto acima é uma solução alternativa não muito elegante (em minha opinião) para usar
Array.map
. Basicamente, faz o seguinte, onde ~ é concatenação:Ele tem o mesmo tempo de execução assintótico que o método abaixo, mas talvez seja um fator constante pior devido à criação de listas vazias. Pode-se reescrever isso da seguinte maneira (principalmente o mesmo método do Blazemonger, razão pela qual eu não enviei originalmente esta resposta):
Método mais eficiente:
Minha maneira preferida atualmente é a acima, ou uma das seguintes opções:
Demo:
Ou, se você não deseja uma função Array.range, na verdade é apenas uma linha (excluindo o buço):
ou
fonte
chunk
função na matriz realmente não supera a complexidade extra que você está adicionando e os erros sutis que mexer com protótipos embutidos pode causar.array.map(function(i)
nãoarray.map(function(elem,i)
emboraAqui está uma versão do ES6 usando o reduzir
E você está pronto para encadear mais mapas / reduzir transformações. Sua matriz de entrada é deixada intacta
Se você preferir uma versão mais curta, mas menos legível, poderá adicionar um pouco
concat
da mistura para o mesmo resultado final:fonte
5/2 = 2.5
eMath.floor(2.5) = 2
assim artigo com índice 5 será colocada no balde 2Tente evitar mexer com protótipos nativos, incluindo Array.prototype, se você não souber quem consumirá seu código (terceiros, colegas de trabalho, você mesmo posteriormente).
Existem maneiras de estender protótipos com segurança (mas não em todos os navegadores) e maneiras de consumir com segurança objetos criados a partir de protótipos estendidos, mas uma regra prática melhor é seguir o Princípio da menor surpresa e evitar essas práticas por completo.
Se você tiver algum tempo, assista à conversa do JSConf 2011 de Andrew Dupont, "Tudo é permitido: estendendo os incorporados" , para uma boa discussão sobre este tópico.
Mas voltando à questão, embora as soluções acima funcionem, elas são excessivamente complexas e exigem sobrecarga computacional desnecessária. Aqui está a minha solução:
fonte
Testei as diferentes respostas em jsperf.com. O resultado está disponível lá: https://web.archive.org/web/20150909134228/https://jsperf.com/chunk-mtds
E a função mais rápida (e que funciona no IE8) é esta:
fonte
Eu preferiria usar o método de emenda :
fonte
var clone = [...array]
faça a verificação e emenda do comprimento sobre essa matriz clonada.array = array.slice()
criar uma cópia superficial.Uma linha no ECMA 6
fonte
list
matriz.map((_,i) => list.slice(i*chuckSize,i*chuckSize+chuckSize))
Pergunta antiga: nova resposta! Na verdade, eu estava trabalhando com uma resposta para essa pergunta e um amigo a melhorou! Então aqui está:
fonte
.length
é muito maior que o tamanho do pedaçon
). Se essa fosse uma linguagem lenta (diferente do javascript), esse algoritmo não sofreria o tempo O (N ^ 2). Dito isto, a implementação recursiva é elegante. Provavelmente, você pode modificá-lo para melhorar o desempenho definindo primeiro uma função auxiliar que recurses emarray,position
, em seguida, despachando:Array.prototype.chunk
retornos [sua função auxiliar] (...)var chunk = (arr, n) => { if ( !arr.length ) return []; return [ arr.slice( 0, n ) ].concat( chunk(arr.slice(n), n) ) }
Atualmente, você pode usar a função chod do lodash 'para dividir a matriz em matrizes menores https://lodash.com/docs#chunk Não é mais necessário mexer nos loops!
fonte
Houve muitas respostas, mas é isso que eu uso:
Primeiro, verifique se há um restante ao dividir o índice pelo tamanho do pedaço.
Se houver um restante, basta retornar a matriz do acumulador.
Se não houver resto, o índice é divisível pelo tamanho do pedaço, então pegue uma fatia da matriz original (iniciando no índice atual) e adicione-a à matriz do acumulador.
Portanto, a matriz do acumulador retornada para cada iteração de redução se parece com isso:
fonte
Usando geradores
fonte
Ok, vamos começar com um bastante apertado:
Que é usado assim:
Então nós temos esta função redutora apertada:
Que é usado assim:
Como um gatinho morre quando vinculamos
this
a um número, podemos fazer curry manual como este:Que é usado assim:
Então a função ainda bastante rígida que faz tudo de uma só vez:
fonte
(p[i/n|0] || (p[i/n|0] = []))
, então você não atribuir um valor, se não for necessário ...Eu pretendia criar uma solução simples e não mutante no ES6 puro. As peculiaridades em javascript tornam necessário preencher a matriz vazia antes de mapear :-(
Esta versão com recursão parece mais simples e mais atraente:
As funções de matriz ridiculamente fracas do ES6 criam bons quebra-cabeças :-)
fonte
0
partir dafill
, o que torna afill
olhar um pouco mais sensato, imho.Eu acho que essa é uma boa solução recursiva com sintaxe ES6:
fonte
Criou um pacote npm para este https://www.npmjs.com/package/array.chunk
Ao usar um TypedArray
fonte
slice
método paraTypedArray
, podemos usarsubarray
em vez developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...Se você usa a versão EcmaScript> = 5.1, pode implementar uma versão funcional do
chunk()
uso de array.reduce () que possui complexidade O (N):Explicação de cada um
// nbr
acima:chunkSize
itensCaril com base em
chunkSize
:Você pode adicionar a
chunk()
função aoArray
objeto global :fonte
fonte
fonte
A seguinte abordagem do ES2015 funciona sem a necessidade de definir uma função e diretamente em matrizes anônimas (exemplo com tamanho de bloco 2):
Se você deseja definir uma função para isso, pode fazê-lo da seguinte forma (melhorando o comentário de K. _ na resposta do Blazemonger ):
fonte
E essa seria minha contribuição para esse tópico. Eu acho que
.reduce()
é o melhor caminho.Mas a implementação acima não é muito eficiente, pois
.reduce()
executa todas asarr
funções. Uma abordagem mais eficiente (muito próxima da solução imperativa mais rápida) seria iterar sobre a matriz reduzida (a ser dividida em partes), pois podemos calcular seu tamanho antecipadamenteMath.ceil(arr/n);
. Uma vez que tenhamos a matriz de resultados vazia,Array(Math.ceil(arr.length/n)).fill();
o restante será mapear fatias daarr
matriz para ele.fonte
Usar pedaço de lodash
fonte
Mais uma solução usando
arr.reduce()
:Esta solução é muito semelhante à solução de Steve Holgado . No entanto, como essa solução não utiliza a dispersão de matriz e não cria novas matrizes na função redutora, é mais rápida (consulte o teste jsPerf ) e subjetivamente mais legível (sintaxe mais simples) do que a outra solução.
A cada enésima iteração (em que n =
size
; iniciando na primeira iteração), a matriz do acumulador (acc
) é anexada com uma parte da matriz (arr.slice(i, i + size)
) e depois retornada. Em outras iterações, a matriz do acumulador é retornada como está.Se
size
for zero, o método retornará uma matriz vazia. Sesize
for negativo, o método retornará resultados quebrados. Portanto, se necessário no seu caso, convém fazer algo sobre valores negativos ou não positivossize
.Se a velocidade for importante no seu caso, um
for
loop simples seria mais rápido do que o usoarr.reduce()
(consulte o teste jsPerf ), e alguns podem achar esse estilo mais legível também:fonte
Para uma solução funcional, usando o Ramda :
Onde
popularProducts
está sua matriz de entrada,5
é o tamanho do pedaçofonte
Abordagem de linha única ES6 com base
Array.prototype
reduce
epush
métodos:fonte
Versão do ES6 Generator
fonte
const
vez disso.Esta é a solução mais eficiente e direta que eu poderia pensar:
fonte
ES6 espalha funcional #ohmy #ftw
fonte
Aqui está uma solução recursiva que é a otimização da chamada final.
fonte
EDIT: @ mblase75 adicionou um código mais conciso à resposta anterior enquanto escrevia o meu, por isso recomendo ir com a solução dele.
Você pode usar código como este:
Altere o valor de
arraySize
para alterar o comprimento máximo das matrizes menores.fonte
Aqui está uma solução não mutante usando apenas recursão e fatia ().
Em seguida, basta usá-lo como
splitToChunks([1, 2, 3, 4, 5], 3)
para obter[[1, 2, 3], [4, 5]]
.Aqui está um violino para você experimentar: https://jsfiddle.net/6wtrbx6k/2/
fonte