Допустим, у меня есть массив Javascript, который выглядит следующим образом:
["Element 1","Element 2","Element 3",...]; // with close to a hundred elements.
Какой подход был бы уместен для разбиения массива на множество меньших массивов, скажем, с 10 элементами максимум?
javascript
arrays
split
промышленные
источник
источник
const chunk = (arr, n) => arr.length ? [arr.slice(0, n), ...chunk(arr.slice(n), n)] : []
что красиво и коротко, но, кажется, занимает примерно 256 × столько же, сколько ответ @ AymKdn для 1000 элементов, и 1058 × столько же для 10 000 элементов!Ответы:
Метод array.slice может извлечь фрагмент из начала, середины или конца массива для любых целей, без каких-либо изменений исходного массива.
источник
chunk
бытия0
. (бесконечный цикл)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));
.Изменено в ответе dbaseman: https://stackoverflow.com/a/10456344/711085
незначительное дополнение :
Я должен отметить, что вышесказанное - не слишком элегантный (на мой взгляд) обходной путь для использования
Array.map
. Это в основном делает следующее, где ~ это конкатенация:Он имеет то же асимптотическое время выполнения, что и метод ниже, но, возможно, имеет худший постоянный коэффициент из-за создания пустых списков. Можно переписать это следующим образом (в основном, так же, как метод Blazemonger, поэтому я изначально не представил этот ответ):
Более эффективный метод:
Мой предпочтительный способ в настоящее время - выше или один из следующих:
Демо-версия:
Или, если вам не нужна функция Array.range, это просто однострочная (исключая пух):
или
источник
chunk
функции в массиве, на самом деле не перевешивает дополнительную сложность, которую вы добавляете, и незаметные ошибки, которые могут возникнуть при работе со встроенными прототипами.array.map(function(i)
неarray.map(function(elem,i)
хотяВот версия ES6, использующая уменьшение
И вы готовы связать дальнейшие карты / уменьшить трансформации. Ваш входной массив остался нетронутым
Если вы предпочитаете более короткую, но менее читаемую версию, вы можете добавить немного
concat
смеси в тот же конечный результат:источник
5/2 = 2.5
иMath.floor(2.5) = 2
поэтому элемент с индексом 5 будет помещен в корзину 2Старайтесь избегать хакерства с нативными прототипами, включая Array.prototype, если вы не знаете, кто будет потреблять ваш код (третьи лица, коллеги, вы позже и т. Д.).
Существуют способы безопасного расширения прототипов (но не во всех браузерах), и есть способы безопасного использования объектов, созданных из расширенных прототипов, но лучшим практическим правилом является следовать принципу наименьшего сюрприза и вообще избегать этих практик.
Если у вас есть время, посмотрите презентацию Andon Dupont JSConf 2011 «Все разрешено: расширение встроенных модулей» , чтобы обсудить эту тему.
Но вернемся к вопросу, хотя приведенные выше решения будут работать, они слишком сложны и требуют ненужных вычислительных затрат. Вот мое решение:
источник
Я проверил разные ответы на jsperf.com. Результат доступен там: https://web.archive.org/web/20150909134228/https://jsperf.com/chunk-mtds
И самая быстрая функция (и это работает с IE8) это:
источник
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; }
Я бы предпочел использовать метод сплайсинга :
источник
var clone = [...array]
затем выполните проверку длины и сращивание этого клонированного массива.array = array.slice()
создать мелкую копию.Однострочник в ECMA 6
источник
list
массив.map((_,i) => list.slice(i*chuckSize,i*chuckSize+chuckSize))
Старый вопрос: новый ответ! Я на самом деле работал с ответом на этот вопрос, и мой друг улучшил его! Итак, вот оно:
источник
.length
размер массива намного превышает размер фрагментаn
). Если бы это был ленивый язык (в отличие от javascript), этот алгоритм не страдал бы за O (N ^ 2) времени. Тем не менее, рекурсивная реализация элегантна. Вероятно, вы можете изменить его, чтобы повысить производительность, сначала определив вспомогательную функцию, которая повторяетсяarray,position
, а затем отправив:Array.prototype.chunk
возвращает [вашу вспомогательную функцию] (...)var chunk = (arr, n) => { if ( !arr.length ) return []; return [ arr.slice( 0, n ) ].concat( chunk(arr.slice(n), n) ) }
В настоящее время вы можете использовать функцию lodash 'chunk, чтобы разделить массив на меньшие массивы. Https://lodash.com/docs#chunk Больше не нужно возиться с циклами!
источник
Было много ответов, но это то, что я использую:
Сначала проверьте остаток при делении индекса на размер куска.
Если есть остаток, просто верните массив аккумуляторов.
Если остатка нет, то индекс делится на размер фрагмента, поэтому возьмите фрагмент из исходного массива (начиная с текущего индекса) и добавьте его в массив аккумулятора.
Итак, возвращаемый массив аккумуляторов для каждой итерации Reduce выглядит примерно так:
источник
Использование генераторов
источник
Хорошо, давайте начнем с довольно узкого:
Который используется так:
Тогда у нас есть эта плотная функция редуктора:
Который используется так:
Так как котенок умирает, когда мы привязываемся
this
к числу, мы можем вместо этого делать карри вручную:Который используется так:
Тогда все еще довольно трудная функция, которая делает все это за один раз:
источник
(p[i/n|0] || (p[i/n|0] = []))
, чтобы вы не присваивали значение, если не нужно ...Я стремился создать простое решение без мутаций в чистом ES6. Особенности в javascript заставляют заполнять пустой массив перед отображением :-(
Эта версия с рекурсией кажется более простой и убедительной:
Смехотворно слабые функции массива ES6 делают для хороших загадок :-)
источник
0
изfill
, что делаетfill
взгляд немного более осмысленным, imho.Я думаю, что это хорошее рекурсивное решение с синтаксисом ES6:
источник
Создан пакет npm для этого https://www.npmjs.com/package/array.chunk
При использовании TypedArray
источник
slice
метода дляTypedArray
, мы можем использоватьsubarray
вместо developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Если вы используете версию EcmaScript> = 5.1, вы можете реализовать функциональную версию с
chunk()
использованием array.reduce ( ) со сложностью O (N):Объяснение каждого
// nbr
выше:chunkSize
элементыКарри на основе
chunkSize
:Вы можете добавить
chunk()
функцию к глобальномуArray
объекту:источник
источник
источник
Следующий подход ES2015 работает без определения функции и непосредственно для анонимных массивов (пример с размером чанка 2):
Если вы хотите определить функцию для этого, вы можете сделать это следующим образом (улучшив комментарий K ._ к ответу Blazemonger ):
источник
И это был бы мой вклад в эту тему. Я думаю,
.reduce()
это лучший способ.Но приведенная выше реализация не очень эффективна, поскольку
.reduce()
проходит через всеarr
функции. Более эффективный подход (очень близкий к самому быстрому императивному решению) заключался бы в итерации по уменьшенному (подлежащему фрагментации) массиву, поскольку мы можем заранее рассчитать его размерMath.ceil(arr/n);
. Как только мы получим пустой массив результатов, какArray(Math.ceil(arr.length/n)).fill();
остальное, нужно отобразить в него фрагментыarr
массива.источник
Используйте кусок от lodash
источник
Еще одно решение с использованием
arr.reduce()
:Это решение очень похоже на решение Стива Холгадо . Однако, поскольку это решение не использует расширение массива и не создает новые массивы в функции редуктора, оно быстрее (см. Тест jsPerf ) и субъективно более читабельно (более простой синтаксис), чем другое решение.
На каждой n-й итерации (где n =
size
; начиная с первой итерации) к массиву-аккумулятору (acc
) добавляется фрагмент массива (arr.slice(i, i + size)
), а затем возвращается. На других итерациях массив аккумуляторов возвращается как есть.Если
size
ноль, метод возвращает пустой массив. Если значениеsize
отрицательное, метод возвращает неверные результаты. Поэтому, если это необходимо в вашем случае, вы можете сделать что-то с отрицательными или неположительнымиsize
значениями.Если в вашем случае важна скорость, простой
for
цикл будет быстрее, чем при использованииarr.reduce()
(см. Тест jsPerf ), и некоторые могут найти этот стиль также более читабельным:источник
Для функционального решения, используя Ramda :
Где
popularProducts
ваш входной массив,5
это размер чанкаисточник
ES6 однострочный подход на основе
Array.prototype
reduce
иpush
методы:источник
ES6 генератор версия
источник
const
вместо этого.Это самое эффективное и простое решение, которое я мог придумать:
источник
ES6 распространяет функционал #ohmy #ftw
источник
Вот рекурсивное решение, которое является хвостовым вызовом оптимизации.
источник
РЕДАКТИРОВАТЬ: @ mblase75 добавил более краткий код к предыдущему ответу, когда я писал свой, поэтому я рекомендую пойти с его решением.
Вы можете использовать такой код:
Измените значение,
arraySize
чтобы изменить максимальную длину меньших массивов.источник
Вот немутантное решение, использующее только рекурсию и slice ().
Тогда просто используйте это как
splitToChunks([1, 2, 3, 4, 5], 3)
получить[[1, 2, 3], [4, 5]]
.Вот скрипка для вас, чтобы попробовать: https://jsfiddle.net/6wtrbx6k/2/
источник