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

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

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

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

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

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

Ответы [ 46 ]

3 голосов
/ 27 марта 2018

Это самое эффективное и простое решение, которое я мог придумать:

function chunk(array, chunkSize) {
    let chunkCount = Math.ceil(array.length / chunkSize);
    let chunks = new Array(chunkCount);
    for(let i = 0, j = 0, k = chunkSize; i < chunkCount; ++i) {
        chunks[i] = array.slice(j, k);
        j = k;
        k += chunkSize;
    }
    return chunks;
}
3 голосов
/ 27 декабря 2016

ES6 Генератор версия

function* chunkArray(array,size=1){
    var clone = array.slice(0);
    while (clone.length>0) 
      yield clone.splice(0,size); 
};
var a = new Array(100).fill().map((x,index)=>index);
for(const c of chunkArray(a,10)) 
    console.log(c);
3 голосов
/ 11 октября 2018

ES6 распространяет функционал #ohmy # ftw

const chunk =
  (size, xs) => 
    xs.reduce(
      (segments, _, index) =>
        index % size === 0 
          ? [...segments, xs.slice(index, index + size)] 
          : segments, 
      []
    );

console.log( chunk(3, [1, 2, 3, 4, 5, 6, 7, 8]) );
2 голосов
/ 09 февраля 2017

Это решение без мутаций, использующее только рекурсию и slice ().

const splitToChunks = (arr, chunkSize, acc = []) => (
    arr.length > chunkSize ?
        splitToChunks(
            arr.slice(chunkSize),
            chunkSize,
            [...acc, arr.slice(0, chunkSize)]
        ) :
        [...acc, arr]
);

Тогда просто используйте его как splitToChunks([1, 2, 3, 4, 5], 3), чтобы получить [[1, 2, 3], [4, 5]].

Вот скрипка, которую вы можете попробовать: https://jsfiddle.net/6wtrbx6k/2/

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

РЕДАКТИРОВАТЬ: @ mblase75 добавил более краткий код к предыдущему ответу, когда я писал свой, поэтому я рекомендую пойти с его решением.

Вы можете использовать код, подобный этому:

var longArray = ["Element 1","Element 2","Element 3", /*...*/];
var smallerArrays = []; // will contain the sub-arrays of 10 elements each
var arraySize = 10;
for (var i=0;i<Math.ceil(longArray.length/arraySize);i++) {
    smallerArrays.push(longArray.slice(i*arraySize,i*arraySize+arraySize));
}

Измените значение arraySize, чтобы изменить максимальную длину меньших массивов.

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

Следующий подход ES2015 работает без определения функции и непосредственно для анонимных массивов (пример с размером чанка 2):

[11,22,33,44,55].map((_, i, all) => all.slice(2*i, 2*i+2)).filter(x=>x.length)

Если вы хотите определить функцию для этого, вы можете сделать это следующим образом (улучшив комментарий К ._ к Ответ Blazemonger ):

const array_chunks = (array, chunk_size) => array
    .map((_, i, all) => all.slice(i*chunk_size, (i+1)*chunk_size))
    .filter(x => x.length)
1 голос
/ 28 мая 2016

Вот мой подход, использующий понимание списка Coffeescript. Отличная статья, детализирующая понимание в Coffeescript, может быть найдена здесь .

chunk: (arr, size) ->
    chunks = (arr.slice(index, index+size) for item, index in arr by size)
    return chunks
1 голос
/ 11 декабря 2015

Я немного изменил BlazeMonger, чтобы использовать его для объекта jQuery.

var $list = $('li'),
    $listRows = [];


for (var i = 0, len = $list.length, chunk = 4, n = 0; i < len; i += chunk, n++) {
   $listRows[n] = $list.slice(i, i + chunk);
}
1 голос
/ 01 июня 2017

Вот аккуратная и оптимизированная реализация функции chunk(). Предполагая, что размер чанка по умолчанию равен 10.

var chunk = function(list, chunkSize) {
  if (!list.length) {
    return [];
  }
  if (typeof chunkSize === undefined) {
    chunkSize = 10;
  }

  var i, j, t, chunks = [];
  for (i = 0, j = list.length; i < j; i += chunkSize) {
    t = list.slice(i, i + chunkSize);
    chunks.push(t);
  }

  return chunks;
};

//calling function
var list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
var chunks = chunk(list);
1 голос
/ 14 января 2016

Я создал следующее JSFiddle , чтобы продемонстрировать мой подход к вашему вопросу.

(function() {
  // Sample arrays
  var //elements = ["0", "1", "2", "3", "4", "5", "6", "7"],
      elements = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43"];

  var splitElements = [],
      delimiter = 10; // Change this value as needed
      
  // parameters: array, number of elements to split the array by
  if(elements.length > delimiter){
  	splitElements = splitArray(elements, delimiter);
  }
  else {
  	// No need to do anything if the array's length is less than the delimiter
  	splitElements = elements;
  }
  
  //Displaying result in console
  for(element in splitElements){
  	if(splitElements.hasOwnProperty(element)){
    	console.log(element + " | " + splitElements[element]);
    }
  }
})();

function splitArray(elements, delimiter) {
  var elements_length = elements.length;

  if (elements_length > delimiter) {
    var myArrays = [], // parent array, used to store each sub array
      first = 0, // used to capture the first element in each sub array
      index = 0; // used to set the index of each sub array

    for (var i = 0; i < elements_length; ++i) {
      if (i % delimiter === 0) {
      	// Capture the first element of each sub array from the original array, when i is a modulus factor of the delimiter.
        first = i;
      } else if (delimiter - (i % delimiter) === 1) {
      // Build each sub array, from the original array, sliced every time the i one minus the modulus factor of the delimiter.
        index = (i + 1) / delimiter - 1;
        myArrays[index] = elements.slice(first, i + 1);
      }
      else if(i + 1 === elements_length){
      	// Build the last sub array which contain delimiter number or less elements
      	myArrays[index + 1] = elements.slice(first, i + 1);
      }
    }
    // Returned is an array of arrays
    return myArrays;
  }
}

Прежде всего, у меня есть два примера: массив с менее чем восемью элементами, другой с массивом с более чем восемью элементами (прокомментируйте тот, который вы не хотитеиспользовать).

Затем я проверяю размер массива, простой, но необходимый, чтобы избежать дополнительных вычислений.Отсюда, если массив соответствует критериям (размер массива> delimiter), мы переходим в функцию splitArray.

Функция splitArray принимает разделитель (имеется в виду 8, поскольку это то, что вы хотитеразделить на), и сам массив.Поскольку мы многократно используем длину массива, я кеширую его в переменной, а также first и last.

first представляет позицию первого элемента вмассив.Этот массив представляет собой массив из 8 элементов.Таким образом, для определения первого элемента мы используем оператор модуля .

myArrays - массив массивов.В нем мы будем хранить в каждом индексе любой вложенный массив размером 8 или ниже.Это ключевая стратегия в алгоритме ниже.

index представляет индекс для переменной myArrays.Каждый раз, когда необходимо сохранить подмассив из 8 элементов или менее, его необходимо сохранить в соответствующем индексе.Итак, если у нас есть 27 элементов, это означает, что 4 массива.Первый, второй и третий массив будут иметь 8 элементов каждый.Последний будет иметь только 3 элемента.Таким образом, index будет 0, 1, 2 и 3. соответственно.

Сложная часть просто вычисляет математику и оптимизирует ее как можно лучше.Например, else if (delimiter - (i % delimiter) === 1) это найти последний элемент, который должен идти в массиве, когда массив будет заполнен (пример: содержит 10 элементов).

Этот код работает для каждого отдельного сценария, вы даже можетеизмените delimiter, чтобы он соответствовал размеру любого массива, который вы хотите получить.Довольно мило, правда: -)

Есть вопросы?Не стесняйтесь спрашивать в комментариях ниже.

...