Разделить массив JavaScript на куски с помощью Lodash


83

Мне нужно разбить массив JavaScript на nкуски определенного размера.

Например: учитывая этот массив

["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"]

и a nравно 4, результат должен быть таким:

[ ["a1", "a2", "a3", "a4"],
  ["a5", "a6", "a7", "a8"],
  ["a9", "a10", "a11", "a12"],
  ["a13"]
]

Мне известны решения этой проблемы на чистом JavaScript , но, поскольку я уже использую Lodash, мне интересно, предоставляет ли Lodash лучшее решение для этой проблемы.

Редактировать:

Я создал тест jsPerf, чтобы проверить, насколько медленнее решение для подчеркивания.

Ответы:


126

Взгляните на кусок lodash : https://lodash.com/docs#chunk

const data = ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"];
const chunks = _.chunk(data, 3);
console.log(chunks);
// [
//  ["a1", "a2", "a3"],
//  ["a4", "a5", "a6"],
//  ["a7", "a8", "a9"],
//  ["a10", "a11", "a12"],
//  ["a13"]
// ]
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>


Было бы полезно, если бы lodash и подчеркивали оба обратно совместимых API
— Jonno_FTW

@Jonah Это правда. Предыдущий ответ уже не является лучшим, поэтому я обновил принятый ответ ради читателей :)
— Сезар Канасса

90

Для решения на основе Underscore попробуйте следующее:

var data = ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"];
var n = 3;
var lists = _.groupBy(data, function(element, index){
  return Math.floor(index/n);
});
lists = _.toArray(lists); //Added this to convert the returned object to an array.
console.log(lists);

Используя метод цепной оболочки, вы можете объединить два оператора, как показано ниже:

var data = ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"];
var n = 3;
var lists = _.chain(data).groupBy(function(element, index){
  return Math.floor(index/n);
}).toArray()
.value();

1
Как ни странно, Underscore groupBy возвращает объект , а не массив. Это не нарушитель договоренностей - вы получаете в основном те же функции, но немного странной семантики. Изменить: О, он делает это для поддержания цепочки. Все еще интересно.
— Jordan Running

@Cesar Canassa: Ради будущих разработчиков, которые читают этот код, подумайте о том, чтобы добавить это как функцию в пользовательскую библиотеку, если вы будете ее
— часто

@Jordan: Не осознавал этого. Отредактировал ответ, чтобы преобразовать объект в массив.
— Chandu

Хотя я за то, чтобы использовать Underscore для того, что он делает лучше всего (и OP запросил решение на основе Underscore, чтобы √ не было незаслуженным) и для функциональных решений, похоже, что это решение вводит массу накладных расходов. Как указывает @ ajax33321, spliceцикл по-прежнему является трехстрочным и, как я предполагаю, намного более производительным. Если ваши массивы короткие, это, вероятно, не имеет значения, но если вы имеете дело с сотнями или тысячами элементов, следите за их производительностью.
— Jordan Running

1
Это уже не лучшее решение. Пожалуйста, используйте вместо него chunk ()
— Иона

4

Возможно более простое выражение:

const coll = [ "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9" ];
const n = 2;
const chunks = _.range(coll.length / n).map(i => coll.slice(i * n, (i + 1) * n));
console.log(chunks);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>


1
Проще чем что? Ответы должны стоять отдельно.
— Натан Тагги

4

Underscore изначально поддерживает _.chunk () начиная с версии 1.9.0.

const data = ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"];
const chunks = _.chunk(data, 4);
console.log(chunks);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore.js"></script>


1

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

function chunk(arr, start, amount){
    var result = [], 
        i, 
        start = start || 0, 
        amount = amount || 500, 
        len = arr.length;

    do {
        //console.log('appending ', start, '-', start + amount, 'of ', len, '.');
        result.push(arr.slice(start, start+amount));
        start += amount;

    } while (start< len);

    return result;
};

и использование в вашем случае:

var arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],
    chunked = chunk(arr, 0, Math.floor(arr.length/3)); //to get 4 nested arrays

console.log(chunked);

и еще один случай:

var arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],
    chunked = chunk(arr, 0, 3); // to get 6 nested arrays each containing maximum of 3 items

console.log(chunked);

Этот startпараметр не очень практичен, imho. Обычно вы не хотите его проходить; но вам всегда нужно указывать размер блока. Лучше поменять местами эти два параметра.
— Берги

Почему это do whileпетля? Никто не хочет получать пустые куски.
— Берги
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.