Podziel tablicę JavaScript na porcje za pomocą Lodash

83

Muszę podzielić tablicę JavaScript na nmniejsze części.

Np .: Biorąc pod uwagę tę tablicę

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

a nrówna się 4, wynik powinien wyglądać następująco:

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

Zdaję sobie sprawę z czystych rozwiązań JavaScript dla tego problemu, ale ponieważ korzystam już z Lodash , zastanawiam się, czy Lodash zapewnia lepsze rozwiązanie tego problemu.

Edytować:

Stworzyłem test jsPerf, aby sprawdzić, o ile wolniejsze jest rozwiązanie podkreślające.

Cesar Canassa
źródło

Odpowiedzi:

126

Spójrz na kawałek 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>

Edo
źródło
Byłoby pomocne, gdybyśmy złożyli i podkreślili oba interfejsy API zgodne z poprzednimi wersjami
Jonno_FTW
@Jonah To prawda. Poprzednia odpowiedź nie jest już najlepsza, dlatego zaktualizowałem zaakceptowaną odpowiedź dla dobra czytelników :)
Cesar Canassa
90

W przypadku rozwiązania opartego na podkreśleniu spróbuj tego:

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);

Używając metody chain wrapper, możesz połączyć te dwie instrukcje jak poniżej:

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();
Chandu
źródło
1
Co dziwne, groupBy funkcja Underscore zwraca obiekt , a nie tablicę. Nie jest to przełom - otrzymujesz zasadniczo tę samą funkcjonalność - ale dziwną semantykę. Edycja: Och, robi to, aby zachować łańcuchowość. Wciąż interesujące.
Jordan działa,
@Cesar Canassa: Ze względu na przyszłych programistów, którzy czytają ten kod, rozważ umieszczenie go jako funkcji w bibliotece niestandardowej, jeśli będziesz go często używać, lub dobrze skomentuj, jeśli nie chcesz :)
Briguy37
@Jordan: Nie zdawałem sobie z tego sprawy. Edytowano odpowiedź, aby przekształcić obiekt w tablicę.
Chandu
Chociaż jestem za używaniem Underscore do rzeczy, które robi najlepiej (a OP poprosił o rozwiązanie oparte na Underscore, więc nie jest niezasłużone) i do rozwiązań funkcjonalnych, wydaje się, że to rozwiązanie wprowadza mnóstwo narzutów. Jak wskazuje @ ajax33321, splicew pętli jest nadal trójliniowy i, jak sądzę, o wiele bardziej wydajny. Jeśli twoje tablice są krótkie, prawdopodobnie nie ma to znaczenia, ale jeśli masz do czynienia z setkami lub tysiącami elementów, miej oko na ich wydajność.
Jordan działa
1
To już nie jest najlepsze rozwiązanie. Zamiast tego użyj chunk ()
Jonah
4

Prawdopodobnie prostsze wyrażenie:

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>

user1009908
źródło
1
Prostsze niż co? Odpowiedzi powinny być samodzielne.
Nathan Tuggy
4

Podkreślenie obsługuje natywnie _.chunk () od wersji 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>

user9027325
źródło
1

spróbuj tego, jest o wiele bardziej praktyczny (na przykład, jeśli chcesz podzielić tablicę na podstawie ilości elementów, które mają być kontenerami w każdej pod macierzy):

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;
};

i zastosowanie w twoim przypadku:

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);

i inny przypadek:

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);
viacheslav marienko
źródło
Ten startparametr nie jest naprawdę praktyczny, imho. Zwykle nie chciałbyś tego zdać; ale zawsze musisz określić rozmiar porcji. Lepiej zamień te dwa parametry.
Bergi
Dlaczego to jest do whilepętla? Nikt nie chce dostawać pustych kawałków.
Bergi