Разбить массив на куски - PullRequest
       164

Разбить массив на куски

396 голосов
/ 14 декабря 2011

Допустим, у меня есть массив Javascript, который выглядит следующим образом:

["Element 1","Element 2","Element 3",...]; // with close to a hundred elements.

Какой подход был бы уместен для разбиения массива на множество меньших массивов, скажем, максимум с 10 элементами?

Ответы [ 46 ]

10 голосов
/ 04 ноября 2017

Я стремился создать простое решение без мутаций в чистом ES6. Особенности в javascript заставляют заполнять пустой массив перед отображением: - (

function chunk(a, l) { 
    return new Array(Math.ceil(a.length / l)).fill(0)
        .map((_, n) => a.slice(n*l, n*l + l)); 
}

Эта версия с рекурсией кажется более простой и убедительной:

function chunk(a, l) { 
    if (a.length == 0) return []; 
    else return [a.slice(0, l)].concat(chunk(a.slice(l), l)); 
}

Смехотворно слабые функции массива ES6 создают хорошие головоломки: -)

9 голосов
/ 16 октября 2018

Я думаю, что это хорошее рекурсивное решение с синтаксисом ES6:

const chunk = function(array, size) {
  if (!array.length) {
    return [];
  }
  const head = array.slice(0, size);
  const tail = array.slice(size);

  return [head, ...chunk(tail, size)];
};

console.log(chunk([1,2,3], 2));
8 голосов
/ 30 мая 2016

Если вы используете версию EcmaScript> = 5.1, вы можете реализовать функциональную версию chunk(), используя array.reduce () со сложностью O (N):

function chunk(chunkSize, array) {
    return array.reduce(function(previous, current) {
        var chunk;
        if (previous.length === 0 || 
                previous[previous.length -1].length === chunkSize) {
            chunk = [];   // 1
            previous.push(chunk);   // 2
        }
        else {
            chunk = previous[previous.length -1];   // 3
        }
        chunk.push(current);   // 4
        return previous;   // 5
    }, []);   // 6
}

console.log(chunk(2, ['a', 'b', 'c', 'd', 'e']));
// prints [ [ 'a', 'b' ], [ 'c', 'd' ], [ 'e' ] ]

Объяснение каждого // nbr выше:

  1. Создать новый чанк, если предыдущее значение, то есть ранее возвращенный массив чанков,пусто или если последний предыдущий чанк содержит chunkSize элементов
  2. Добавить новый чанк в массив существующих чанков
  3. В противном случае текущий чанк является последним чанком в массиве чанков
  4. Добавить текущее значение к чану
  5. Вернуть измененный массив чанков
  6. Инициализировать сокращение, передав пустой массив

Curryна основе chunkSize:

var chunk3 = function(array) {
    return chunk(3, array);
};

console.log(chunk3(['a', 'b', 'c', 'd', 'e']));
// prints [ [ 'a', 'b', 'c' ], [ 'd', 'e' ] ]

Вы можете добавить функцию chunk() к глобальному Array объекту:

Object.defineProperty(Array.prototype, 'chunk', {
    value: function(chunkSize) {
        return this.reduce(function(previous, current) {
            var chunk;
            if (previous.length === 0 || 
                    previous[previous.length -1].length === chunkSize) {
                chunk = [];
                previous.push(chunk);
            }
            else {
                chunk = previous[previous.length -1];
            }
            chunk.push(current);
            return previous;
        }, []);
    }
});

console.log(['a', 'b', 'c', 'd', 'e'].chunk(4));
// prints [ [ 'a', 'b', 'c' 'd' ], [ 'e' ] ]
7 голосов
/ 11 апреля 2014
in coffeescript:

b = (a.splice(0, len) while a.length)

demo 
a = [1, 2, 3, 4, 5, 6, 7]

b = (a.splice(0, 2) while a.length)
[ [ 1, 2 ],
  [ 3, 4 ],
  [ 5, 6 ],
  [ 7 ] ]
7 голосов
/ 06 января 2017
results = []
chunk_size = 10
while(array.length > 0){
   results.push(array.splice(0, chunk_size))
}
7 голосов
/ 08 июня 2018

Было дано много ответов, но я использую это:

const chunk = (arr, size) =>
  arr
    .reduce((acc, _, i) =>
      (i % size)
        ? acc
        : [...acc, arr.slice(i, i + size)]
    , [])

// USAGE
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
chunk(numbers, 3)

// [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]

Сначала проверьте остаток при делении индекса на размер куска.

Если есть остатокзатем просто верните массив аккумулятора.

Если остатка нет, то индекс делится на размер куска, поэтому возьмите фрагмент из исходного массива (начиная с текущего индекса) и добавьте его в массив аккумулятора..

Итак, возвращаемый массив аккумуляторов для каждой итерации Reduce выглядит примерно так:

// 0: [[1, 2, 3, 4]]
// 1: [[1, 2, 3, 4]]
// 2: [[1, 2, 3, 4]]
// 3: [[1, 2, 3, 4]]
// 4: [[1, 2, 3, 4], [5, 6, 7, 8]]
// 5: [[1, 2, 3, 4], [5, 6, 7, 8]]
// 6: [[1, 2, 3, 4], [5, 6, 7, 8]]
// 7: [[1, 2, 3, 4], [5, 6, 7, 8]]
// 8: [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]
// 9: [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]
5 голосов
/ 22 мая 2017

И это был бы мой вклад в эту тему. Я думаю, .reduce() это лучший способ.

var segment = (arr, n) => arr.reduce((r,e,i) => i%n ? (r[r.length-1].push(e), r)
                                                    : (r.push([e]), r), []),
        arr = Array.from({length: 31}).map((_,i) => i+1);
        res = segment(arr,7);
console.log(JSON.stringify(res));

Но приведенная выше реализация не очень эффективна, поскольку .reduce() проходит через все функции arr. Более эффективный подход (очень близкий к самому быстрому императивному решению) заключался бы в итерации по уменьшенному (подлежащему фрагментации) массиву, поскольку мы можем заранее рассчитать его размер на Math.ceil(arr/n);. Как только у нас будет пустой массив результатов, такой как Array(Math.ceil(arr.length/n)).fill();, остальное - отобразить в него фрагменты массива arr.

function chunk(arr,n){
  var r = Array(Math.ceil(arr.length/n)).fill();
  return r.map((e,i) => arr.slice(i*n, i*n+n));
}

arr = Array.from({length: 31},(_,i) => i+1);
res = chunk(arr,7);
console.log(JSON.stringify(res));
5 голосов
/ 18 января 2016

Создан пакет npm для этого https://www.npmjs.com/package/array.chunk

  var result = [];
  for (var i = 0; i < arr.length; i += size) {
    result.push(arr.slice(i, size + i));
  }

  return result;
4 голосов
/ 31 марта 2019

Использование генераторов

function* chunks(arr, n) {
 for(let i = 0; i < arr.length; i += n) {
     yield(arr.slice(i, i+n));
     }
}
let someArray = [0,1,2,3,4,5,6,7,8,9]
[...chunks(someArray, 2)] // [[0,1],[2,3],[4,5],[6,7],[8,9]]
4 голосов
/ 16 декабря 2017

ES6 однострочный подход на основе методов Array.prototype reduce и push:

const doChunk = (list, size) => list.reduce((r, v) =>
  (!r.length || r[r.length - 1].length === size ?
    r.push([v]) : r[r.length - 1].push(v)) && r
, []);

console.log(doChunk([0,1,2,3,4,5,6,7,8,9,10,11,12], 5));
// [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12]]
...