Розбийте масив JavaScript на шматки, використовуючи Lodash


83

Мені потрібно розділити масив JavaScript на nвеликі шматки.

Наприклад: Враховуючи цей масив

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

і 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

Для рішення на основі підкреслення спробуйте наступне:

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 повертає об’єкт , а не масив. Не компрометаж - ви отримуєте в основному однакову функціональність, - але дивний шматок семантики. Редагувати: О, це робить це, щоб зберегти привабливість. Все ще цікаво.
Йорданія, біг

@Cesar Canassa: Для майбутніх розробників, які читають цей код, будь ласка, подумайте про те, щоб помістити це як функцію в користувацьку бібліотеку, якщо ви багато будете його використовувати, або добре прокоментувати, якщо ні :)
Briguy37

@Jordan: Не розумів цього. Відредаговано відповідь для перетворення об’єкта в масив.
Chandu

Хоча я все для того, щоб використовувати Underscore для речей, які він робить найкраще (і OP попросив рішення на основі Underscore, щоб не було незаслуженим), а також для функціональних рішень, здається, це рішення призводить до тонни накладних витрат. Як зазначає @ ajax33321, spliceу циклі все ще є три вкладиші і, я здогадуюсь, набагато ефективніші. Якщо ваші масиви короткі, це, мабуть, не має значення, але якщо ви маєте справу з сотнями або тисячами елементів, слідкуйте за його ефективністю.
Йорданія, біг

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

Підкреслення підтримує _.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параметр насправді не є практичним імхо. Зазвичай ви не хочете його пройти; але завжди потрібно вказувати розмір шматка. Краще поміняти ці два параметри місцями.
Бергі

Чому це do whileцикл? Ніхто не хоче отримувати порожні шматки.
Бергі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.