Digamos que tengo una matriz Javascript que se ve de la siguiente manera:
["Element 1","Element 2","Element 3",...]; // with close to a hundred elements.
¿Qué enfoque sería apropiado para fragmentar (dividir) la matriz en muchas matrices más pequeñas con, digamos, 10 elementos como máximo?
javascript
arrays
split
Industrial
fuente
fuente
const chunk = (arr, n) => arr.length ? [arr.slice(0, n), ...chunk(arr.slice(n), n)] : []
que es bueno y corto pero parece tomar alrededor de 256 × el tiempo que la respuesta de @ AymKdn para 1,000 elementos, y 1,058 × tanto como para 10,000 elementos!Respuestas:
El método array.slice puede extraer un segmento desde el principio, el medio o el final de una matriz para cualquier propósito que necesite, sin cambiar la matriz original.
fuente
chunk
ser0
. (bucle 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 una respuesta de dbaseman: https://stackoverflow.com/a/10456344/711085
anexo menor :
Debo señalar que lo anterior es una solución no tan elegante (en mi opinión) para usar
Array.map
. Básicamente hace lo siguiente, donde ~ es concatenación:Tiene el mismo tiempo de ejecución asintótico que el método siguiente, pero quizás un factor constante peor debido a la creación de listas vacías. Uno podría reescribir esto de la siguiente manera (principalmente el mismo que el método de Blazemonger, por lo que originalmente no envié esta respuesta):
Método más eficiente:
Mi forma preferida hoy en día es la anterior, o una de las siguientes:
Manifestación:
O si no desea una función Array.range, en realidad es solo una línea (excluyendo la pelusa):
o
fuente
chunk
función en la matriz realmente no supera la complejidad adicional que estás agregando y los errores sutiles que pueden causar los juegos con los prototipos incorporados.array.map(function(i)
array.map(function(elem,i)
Aquí hay una versión ES6 que usa reducir
Y está listo para encadenar más mapas / reducir transformaciones. Su matriz de entrada se deja intacta
Si prefiere una versión más corta pero menos legible, puede espolvorear un poco
concat
en la mezcla para obtener el mismo resultado final:fuente
5/2 = 2.5
yMath.floor(2.5) = 2
entonces el artículo con el índice 5 se colocará en el cubo 2Intente evitar mucking con prototipos nativos, incluido Array.prototype, si no sabe quién consumirá su código (terceros, compañeros de trabajo, usted mismo en una fecha posterior, etc.).
Hay formas de extender los prototipos de manera segura (pero no en todos los navegadores) y hay formas de consumir de manera segura los objetos creados a partir de prototipos extendidos, pero una mejor regla general es seguir el Principio de Menos Sorpresa y evitar estas prácticas por completo.
Si tiene algo de tiempo, mire la charla JSConf 2011 de Andrew Dupont, "Todo está permitido: ampliación de los elementos integrados" , para una buena discusión sobre este tema.
Pero volviendo a la pregunta, si bien las soluciones anteriores funcionarán, son demasiado complejas y requieren una sobrecarga computacional innecesaria. Aquí está mi solución:
fuente
Probé las diferentes respuestas en jsperf.com. El resultado está disponible allí: https://web.archive.org/web/20150909134228/https://jsperf.com/chunk-mtds
Y la función más rápida (y que funciona desde IE8) es esta:
fuente
function chunk<T>(array: T[], chunkSize: number): T[][] { const R = []; for (let i = 0, len = array.length; i < len; i += chunkSize) R.push(array.slice(i, i + chunkSize)); return R; }
Prefiero usar el método de empalme :
fuente
var clone = [...array]
luego verifique la longitud y empalme sobre esa matriz clonada.array = array.slice()
crear una copia superficial.One-liner en ECMA 6
fuente
list
matriz original.map((_,i) => list.slice(i*chuckSize,i*chuckSize+chuckSize))
Vieja pregunta: nueva respuesta! ¡De hecho, estaba trabajando con una respuesta de esta pregunta y un amigo mejoró! Asi que aqui esta:
fuente
.length
es mucho mayor que el tamaño del fragmenton
). Si se tratara de un lenguaje vago (a diferencia de javascript), este algoritmo no sufriría el tiempo O (N ^ 2). Dicho esto, la implementación recursiva es elegante. Probablemente pueda modificarlo para mejorar el rendimiento definiendo primero una función auxiliar que se repitaarray,position
y luego despachando:Array.prototype.chunk
devuelve [su función auxiliar] (...)var chunk = (arr, n) => { if ( !arr.length ) return []; return [ arr.slice( 0, n ) ].concat( chunk(arr.slice(n), n) ) }
Hoy en día puede usar la función lodash 'chunk para dividir el conjunto en conjuntos más pequeños https://lodash.com/docs#chunk ¡ Ya no es necesario jugar con los bucles!
fuente
Ha habido muchas respuestas pero esto es lo que uso:
Primero, verifique si hay un resto al dividir el índice por el tamaño del fragmento.
Si hay un resto, simplemente devuelva la matriz del acumulador.
Si no hay resto, entonces el índice es divisible por el tamaño del fragmento, por lo tanto, tome un corte de la matriz original (comenzando en el índice actual) y agréguelo a la matriz del acumulador.
Entonces, la matriz de acumulador devuelta para cada iteración de reducción se ve así:
fuente
Usando generadores
fuente
Ok, comencemos con uno bastante ajustado:
Que se usa así:
Entonces tenemos esta estrecha función reductora:
Que se usa así:
Dado que un gatito muere cuando nos unimos
this
a un número, podemos hacer curry manual como este:Que se usa así:
Luego, la función todavía bastante ajustada que lo hace todo de una vez:
fuente
(p[i/n|0] || (p[i/n|0] = []))
, por lo que no se asigna un valor, si no es necesario ...Apunté a crear una solución simple no mutante en ES6 puro. Las peculiaridades en javascript hacen que sea necesario llenar la matriz vacía antes de mapear :-(
Esta versión con recursión parece más simple y más convincente:
Las funciones de matriz ridículamente débiles de ES6 hacen buenos rompecabezas :-)
fuente
0
delfill
, que hace que lafill
mirada un poco más sensible, en mi humilde opinión.Creo que esta es una buena solución recursiva con la sintaxis ES6:
fuente
Creó un paquete npm para este https://www.npmjs.com/package/array.chunk
Cuando use un TypedArray
fuente
slice
método paraTypedArray
, podemos usarsubarray
en su lugar developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Si usa la versión EcmaScript> = 5.1, puede implementar una versión funcional del
chunk()
uso de array.reduce () que tiene complejidad O (N):Explicación de cada uno de los
// nbr
anteriores:chunkSize
elementosCurry basado en
chunkSize
:Puede agregar la
chunk()
función alArray
objeto global :fuente
fuente
fuente
El siguiente enfoque de ES2015 funciona sin tener que definir una función y directamente en matrices anónimas (ejemplo con tamaño de fragmento 2):
Si desea definir una función para esto, puede hacerlo de la siguiente manera (mejorando el comentario de K ._ sobre la respuesta de Blazemonger ):
fuente
Y esta sería mi contribución a este tema. Supongo que
.reduce()
es la mejor manera.Pero la implementación anterior no es muy eficiente ya que
.reduce()
ejecuta todas lasarr
funciones. Sería un enfoque más eficiente (muy cercano a la solución imperativa más rápida), iterar sobre la matriz reducida (para ser fragmentada) ya que podemos calcular su tamaño por adelantadoMath.ceil(arr/n);
. Una vez que tengamos la matriz de resultados vacía,Array(Math.ceil(arr.length/n)).fill();
el resto es mapear rebanadas de laarr
matriz en ella.fuente
Usa trozos de lodash
fuente
Una solución más usando
arr.reduce()
:Esta solución es muy similar a la solución de Steve Holgado . Sin embargo, debido a que esta solución no utiliza la distribución de la matriz y no crea nuevas matrices en la función reductora, es más rápida (ver prueba jsPerf ) y subjetivamente más legible (sintaxis más simple) que la otra solución.
En cada enésima iteración (donde n =
size
; comenzando en la primera iteración), la matriz del acumulador (acc
) se agrega con un fragmento de la matriz (arr.slice(i, i + size)
) y luego se devuelve. En otras iteraciones, la matriz del acumulador se devuelve tal cual.Si
size
es cero, el método devuelve una matriz vacía. Sisize
es negativo, el método devuelve resultados rotos. Entonces, si es necesario en su caso, es posible que desee hacer algo sobresize
valores negativos o no positivos .Si la velocidad es importante en su caso, un
for
bucle simple sería más rápido que usarloarr.reduce()
(vea la prueba jsPerf ), y algunos también pueden encontrar este estilo más legible:fuente
Para una solución funcional, usando Ramda :
¿Dónde
popularProducts
está su matriz de entrada,5
es el tamaño del fragmentofuente
Enfoque de una línea ES6 basado en
Array.prototype
reduce
ypush
métodos:fuente
Versión del generador ES6
fuente
const
lugar.Esta es la solución más eficiente y directa que se me ocurre:
fuente
ES6 se extiende funcional #ohmy #ftw
fuente
Aquí hay una solución recursiva que es la optimización de la llamada de cola.
fuente
EDITAR: @ mblase75 agregó un código más conciso a la respuesta anterior mientras escribía el mío, por lo que recomiendo ir con su solución.
Podrías usar un código como este:
Cambie el valor de
arraySize
para cambiar la longitud máxima de las matrices más pequeñas.fuente
Aquí hay una solución no mutante que usa solo recursión y slice ().
Luego, simplemente úsalo
splitToChunks([1, 2, 3, 4, 5], 3)
para obtener[[1, 2, 3], [4, 5]]
.Aquí hay un violín que puede probar: https://jsfiddle.net/6wtrbx6k/2/
fuente