Pisahkan array menjadi potongan-potongan

516

Katakanlah saya memiliki array Javascript yang terlihat sebagai berikut:

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

Pendekatan apa yang cocok untuk memotong (memecah) array menjadi banyak array yang lebih kecil dengan, katakanlah, 10 elemen paling banyak?

Industri
sumber
Kemungkinan duplikat Memisahkan array JS ke dalam array N
TJ
24
Untuk pengguna lodash , Anda mencari _.chunk .
Ulysse BN
2
Saya baru saja mencoba const chunk = (arr, n) => arr.length ? [arr.slice(0, n), ...chunk(arr.slice(n), n)] : []yang bagus dan pendek tetapi tampaknya memakan waktu sekitar 256 × selama jawaban @ AymKdn untuk 1.000 elemen, dan 1.058 × selama 10.000 elemen!
Toph
jika Anda memerlukan ukuran minimum dari potongan terakhir juga, berikut adalah opsi: stackoverflow.com/questions/57908133/…
Ahmet Cetin

Jawaban:

642

The array.slice Metode dapat mengekstrak sepotong dari awal, tengah, atau akhir array untuk tujuan apa pun yang Anda butuhkan, tanpa mengubah array asli.

var i,j,temparray,chunk = 10;
for (i=0,j=array.length; i<j; i+=chunk) {
    temparray = array.slice(i,i+chunk);
    // do whatever
}
Blazemonger
sumber
19
Ingatlah jika ini adalah fungsi util untuk menegaskan chunkkeberadaan 0. (infinite loop)
Steven Lu
19
Tidak, potongan terakhir seharusnya hanya lebih kecil dari yang lain.
Blazemonger
7
@Blazemonger, memang! Lain kali saya benar-benar akan mencobanya sendiri sebelum langsung ke kesimpulan. Saya berasumsi (secara tidak benar) bahwa mengirimkan input ke array.slice yang melebihi batas array akan menjadi masalah, tetapi bekerja dengan sempurna!
rysqui
55
Untuk satu-liners (chain-pecinta) : const array_chunks = (array, chunk_size) => Array(Math.ceil(array.length / chunk_size)).fill().map((_, index) => index * chunk_size).map(begin => array.slice(begin, begin + chunk_size));.
Константин Ван
8
Kenapa kamu butuh j? Pertama saya pikir ini adalah optimasi, tetapi sebenarnya lebih lambat daripada untuk (i = 0; i <array.length; i ++) {}
Alex
149

Dimodifikasi dari jawaban oleh dbaseman: https://stackoverflow.com/a/10456344/711085

Object.defineProperty(Array.prototype, 'chunk_inefficient', {
  value: function(chunkSize) {
    var array = this;
    return [].concat.apply([],
      array.map(function(elem, i) {
        return i % chunkSize ? [] : [array.slice(i, i + chunkSize)];
      })
    );
  }
});

console.log(
  [1, 2, 3, 4, 5, 6, 7].chunk_inefficient(3)
)
// [[1, 2, 3], [4, 5, 6], [7]]


tambahan kecil :

Saya harus menunjukkan bahwa solusi di atas adalah tidak-elegan (dalam pikiran saya) untuk digunakan Array.map. Ini pada dasarnya melakukan hal berikut, di mana ~ adalah gabungan:

[[1,2,3]]~[]~[]~[] ~ [[4,5,6]]~[]~[]~[] ~ [[7]]

Ini memiliki waktu berjalan asimptotik yang sama dengan metode di bawah ini, tetapi mungkin faktor konstan yang lebih buruk karena membangun daftar kosong. Orang dapat menulis ulang ini sebagai berikut (kebanyakan sama dengan metode Blazemonger, itulah sebabnya saya awalnya tidak mengirimkan jawaban ini):

Metode yang lebih efisien:

// refresh page if experimenting and you already defined Array.prototype.chunk

Object.defineProperty(Array.prototype, 'chunk', {
  value: function(chunkSize) {
    var R = [];
    for (var i = 0; i < this.length; i += chunkSize)
      R.push(this.slice(i, i + chunkSize));
    return R;
  }
});

console.log(
  [1, 2, 3, 4, 5, 6, 7].chunk(3)
)


Cara yang saya sukai saat ini adalah di atas, atau salah satu dari yang berikut:

Array.range = function(n) {
  // Array.range(5) --> [0,1,2,3,4]
  return Array.apply(null,Array(n)).map((x,i) => i)
};

Object.defineProperty(Array.prototype, 'chunk', {
  value: function(n) {

    // ACTUAL CODE FOR CHUNKING ARRAY:
    return Array.range(Math.ceil(this.length/n)).map((x,i) => this.slice(i*n,i*n+n));

  }
});

Demo:

> JSON.stringify( Array.range(10).chunk(3) );
[[1,2,3],[4,5,6],[7,8,9],[10]]

Atau jika Anda tidak ingin fungsi Array.range, sebenarnya hanya satu-liner (tidak termasuk fluff):

var ceil = Math.ceil;

Object.defineProperty(Array.prototype, 'chunk', {value: function(n) {
    return Array(ceil(this.length/n)).fill().map((_,i) => this.slice(i*n,i*n+n));
}});

atau

Object.defineProperty(Array.prototype, 'chunk', {value: function(n) {
    return Array.from(Array(ceil(this.length/n)), (_,i)=>this.slice(i*n,i*n+n));
}});
ninjagecko
sumber
41
Eh, saya akan menghindari bermain-main dengan prototipe karena perasaan kesejukan yang Anda dapatkan dari memanggil chunkfungsi pada array tidak benar-benar melebihi kompleksitas tambahan yang Anda tambahkan dan bug halus yang dapat menyebabkan prototipe built-in dapat menyebabkan.
Gordon Gustafson
12
Dia tidak main-main dengan mereka, dia memperluas mereka untuk Arays. Saya mengerti tidak pernah menyentuh Object.prototype karena itu akan menggelembung ke semua objek (semuanya) tetapi untuk fungsi spesifik Array ini saya tidak melihat masalah.
rlemon
Cukup yakin bahwa seharusnya array.map(function(i)tidak array.map(function(elem,i)meskipun
Nigel Malaikat
3
Berdasarkan bagan kompatibilitas pada situs dev mozilla, Array.map untuk untuk IE9 +. Hati-hati.
Maikel D
Hati-hati untuk lulus mengambang - 7,5 jenis angka - mengarah ke bongkahan yang tidak dapat diprediksi
Gal Bracha
103

Berikut ini adalah versi ES6 menggunakan pengurangan

var perChunk = 2 // items per chunk    

var inputArray = ['a','b','c','d','e']

var result = inputArray.reduce((resultArray, item, index) => { 
  const chunkIndex = Math.floor(index/perChunk)

  if(!resultArray[chunkIndex]) {
    resultArray[chunkIndex] = [] // start a new chunk
  }

  resultArray[chunkIndex].push(item)

  return resultArray
}, [])

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

Dan Anda siap untuk membuat rantai lebih lanjut peta / mengurangi transformasi. Array input Anda dibiarkan utuh


Jika Anda lebih suka versi yang lebih pendek tetapi kurang mudah dibaca, Anda dapat memercikkannya concatke dalam campuran untuk hasil akhir yang sama:

inputArray.reduce((all,one,i) => {
   const ch = Math.floor(i/perChunk); 
   all[ch] = [].concat((all[ch]||[]),one); 
   return all
}, [])
Andrei R
sumber
Ini sepertinya solusi yang paling kental. Apa yang diperoleh chunkIndex = Math.floor (index / perChunk)? Apakah ini rata-rata?
me-me
5/2 = 2.5dan Math.floor(2.5) = 2item dengan indeks 5 akan ditempatkan di bucket 2
Andrei R
Terima kasih Andrei R. Ah jadi langkah 0 - 2. Jadi apa ini disebut dalam istilah Matematika? Saya kira maksud saya adalah saya tidak akan pernah berpikir untuk membagi indeks / 2 setiap indeks untuk mendapatkan indeks dari setiap slice. Jadi saya mencoba untuk membungkus kepala saya karena saya sangat menyukainya tetapi tidak sepenuhnya memahaminya dalam istilah Matematika. Saya biasanya melakukan ini untuk mendapatkan rata-rata dari jumlah total tetapi ini terlihat berbeda.
me-me
Solusi ini tidak efisien jika dibandingkan dengan solusi lain karena Anda perlu mengulangi setiap elemen.
JP de la Torre
Anda benar @JPdelaTorre, mungkin tidak seefisien solusi yang mengiris array, tetapi Anda membelah rambut di sini. sebagian besar jawaban yang tercantum akan tidak efisien dengan definisi itu.
Andrei R
102

Cobalah untuk menghindari mucking dengan prototipe asli, termasuk Array.prototype, jika Anda tidak tahu siapa yang akan mengkonsumsi kode Anda (pihak ke-3, rekan kerja, diri Anda di kemudian hari, dll.).

Ada beberapa cara untuk memperluas prototipe dengan aman (tetapi tidak di semua browser) dan ada cara-cara untuk menggunakan objek yang dibuat dari prototipe yang diperluas dengan aman, tetapi aturan praktis yang lebih baik adalah mengikuti Prinsip Terkejut dan menghindari praktik-praktik ini sama sekali.

Jika Anda punya waktu, lihat pembicaraan Andrew Dupont JSConf 2011, "Semuanya Diizinkan: Memperluas Built-in" , untuk diskusi yang baik tentang topik ini.

Tetapi kembali ke pertanyaan, sementara solusi di atas akan bekerja, mereka terlalu rumit dan membutuhkan overhead komputasi yang tidak perlu. Inilah solusi saya:

function chunk (arr, len) {

  var chunks = [],
      i = 0,
      n = arr.length;

  while (i < n) {
    chunks.push(arr.slice(i, i += len));
  }

  return chunks;
}

// Optionally, you can do the following to avoid cluttering the global namespace:
Array.chunk = chunk;
furf
sumber
25
"hindari mucking dengan prototipe asli" pengembang js baru harus mendapatkan tato dari frase ini untuk sementara, jika tidak permanen.
Jacob Dalton
2
Saya telah menggunakan javascript selama bertahun-tahun dan menghabiskan waktu tanpa repot dengan prototipe, pada sebagian besar fungsi panggilan, tidak pernah memodifikasi seperti yang Anda lihat dilakukan beberapa orang.
1984
2
saran terbaik di mata saya, yang paling sederhana untuk dipahami dan dalam implementasi, terima kasih banyak!
Olga Farber
1
@ Jacobalton Saya pikir ini semua salah universitas. Orang-orang berpikir OOP harus digunakan di mana-mana. Jadi mereka takut "hanya membuat fungsi". Mereka ingin memastikan untuk memasukkannya ke dalam sesuatu. Bahkan jika itu tidak tepat sama sekali. Jika tidak ada notasi titik, tidak ada "arsitektur".
Gherman
51

Saya menguji jawaban yang berbeda ke jsperf.com. Hasilnya tersedia di sana: https://web.archive.org/web/20150909134228/https://jsperf.com/chunk-mtds

Dan fungsi tercepat (dan yang berfungsi dari IE8) adalah yang ini:

function chunk(arr, chunkSize) {
  var R = [];
  for (var i=0,len=arr.length; i<len; i+=chunkSize)
    R.push(arr.slice(i,i+chunkSize));
  return R;
}
AymKdn
sumber
1
Terima kasih @AymKdn untuk membuat tolok ukur ini: Ini sangat membantu! Saya menggunakan pendekatan splice dan itu menghancurkan browser Chrome v70 saya pada ukuran 884432. Dengan pendekatan "slice" yang disarankan, kode saya tidak lagi merusak proses "render" browser. :)
Benny Neugebauer
34

Saya lebih suka menggunakan metode sambatan :

var chunks = function(array, size) {
  var results = [];
  while (array.length) {
    results.push(array.splice(0, size));
  }
  return results;
};
Arek Flinik
sumber
16
Harus berhati-hati dengan solusi sambungan ini karena memodifikasi array asli, jadi pastikan untuk mendokumentasikan efek sampingnya.
bdrx
3
Kemudian gunakan slice sebagai gantinya
mplungjan
@ mplungjan Hasilnya akan menjadi array yang sama berulang kali saat menggunakan slice. Jadi itu bukan pengganti drop-in tanpa modifikasi lagi.
nietonfir
Satu-satunya hal yang akan saya tambahkan ke jawaban ini adalah klon ke array asli. Saya akan melakukannya dengan operator penyebaran ES6. var clone = [...array]kemudian lakukan pemeriksaan panjang dan splicing pada array yang dikloning itu.
MauricioLeal
1
Atau jika Anda tidak dapat menggunakan fitur ES6 Anda dapat dengan sederhana array = array.slice()yang juga membuat salinan dangkal.
3limin4t0r
34

One-liner dalam ECMA 6

const [list,chuckSize] = [[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], 6]

new Array(Math.ceil(list.length / chuckSize)).fill().map(_ => list.splice(0,chuckSize))
Shairon Toledo
sumber
9
itu memodifikasi listarray asli
Jacka
6
Perbaikan mudah menggunakan .slice () .. .map((_,i) => list.slice(i*chuckSize,i*chuckSize+chuckSize))
James Robey
2
Pada JSPerf ini jauh lebih berkinerja daripada banyak jawaban lainnya.
Micah Henning
30

Pertanyaan lama: Jawaban baru! Saya sebenarnya bekerja dengan jawaban dari pertanyaan ini dan meminta seorang teman untuk memperbaikinya! Jadi begini:

Array.prototype.chunk = function ( n ) {
    if ( !this.length ) {
        return [];
    }
    return [ this.slice( 0, n ) ].concat( this.slice(n).chunk(n) );
};

[1,2,3,4,5,6,7,8,9,0].chunk(3);
> [[1,2,3],[4,5,6],[7,8,9],[0]]
rlemon
sumber
14
fyi, kinerja metode ini adalah O (N ^ 2), jadi tidak boleh digunakan di bagian kode yang kritis-kinerja, atau dengan array panjang (khususnya, ketika array .lengthjauh lebih besar daripada ukuran chunk n). Jika ini adalah bahasa yang malas (tidak seperti javascript), algoritma ini tidak akan menderita waktu O (N ^ 2). Yang mengatakan, implementasi rekursif elegan. Anda mungkin dapat memodifikasinya untuk meningkatkan kinerja dengan terlebih dahulu mendefinisikan fungsi pembantu yang berulang array,position, kemudian mengirim: Array.prototype.chunkmengembalikan [fungsi pembantu Anda] (...)
ninjagecko
terimakasih sensai karena memberkati saya dengan roh Anda yang pasti saya lepaskan malam ini
digigit
1
atau ...var chunk = (arr, n) => { if ( !arr.length ) return []; return [ arr.slice( 0, n ) ].concat( chunk(arr.slice(n), n) ) }
Ed Williams
28

Saat ini Anda dapat menggunakan fungsi chunk lodash untuk memecah array menjadi array yang lebih kecil https://lodash.com/docs#chunk Tidak perlu bermain-main lagi dengan loop!

George Herolyants
sumber
3
Saya merasa harus ada penolakan untuk pertanyaan javascript SO: apakah Anda sudah mencoba lodash? Cukup banyak hal pertama yang saya sertakan dalam node atau browser.
Jacob Dalton
20

Ada banyak jawaban tetapi inilah yang saya gunakan:

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]]

Pertama, periksa sisa ketika membagi indeks dengan ukuran chunk.

Jika ada sisa maka kembalikan saja array akumulator.

Jika tidak ada sisa maka indeks dapat dibagi dengan ukuran chunk, jadi ambil irisan dari array asli (mulai dari indeks saat ini) dan tambahkan ke array akumulator.

Jadi, array akumulator yang dikembalikan untuk setiap iterasi dari pengurangan terlihat seperti ini:

// 0: [[1, 2, 3]]
// 1: [[1, 2, 3]]
// 2: [[1, 2, 3]]
// 3: [[1, 2, 3], [4, 5, 6]]
// 4: [[1, 2, 3], [4, 5, 6]]
// 5: [[1, 2, 3], [4, 5, 6]]
// 6: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
// 7: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
// 8: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
// 9: [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
Steve Holgado
sumber
Solusi yang bagus dan representasi visual yang bagus dari iterasi. Saya berakhir dengan solusi yang sangat mirip yang saya posting sebagai jawaban: stackoverflow.com/a/60779547
mts knn
15

Menggunakan generator

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]
console.log([...chunks(someArray, 2)]) // [[0,1],[2,3],[4,5],[6,7],[8,9]]

Ikechukwu Eze
sumber
3
Saya terkejut dengan semua jawaban untuk pertanyaan ini yang hampir menggunakan generator atau menggunakannya dengan cara yang lebih rumit. Keringkasan dan kinerja yang bagus dengan solusi ini.
Keith
14

Ok, mari kita mulai dengan yang cukup ketat:

function chunk(arr, n) {
    return arr.slice(0,(arr.length+n-1)/n|0).
           map(function(c,i) { return arr.slice(n*i,n*i+n); });
}

Yang digunakan seperti ini:

chunk([1,2,3,4,5,6,7], 2);

Maka kita memiliki fungsi peredam ketat ini:

function chunker(p, c, i) {
    (p[i/this|0] = p[i/this|0] || []).push(c);
    return p;
}

Yang digunakan seperti ini:

[1,2,3,4,5,6,7].reduce(chunker.bind(3),[]);

Karena anak kucing mati ketika kita mengikat thisnomor, kita dapat melakukan kari manual seperti ini sebagai gantinya:

// Fluent alternative API without prototype hacks.
function chunker(n) {
   return function(p, c, i) {
       (p[i/n|0] = p[i/n|0] || []).push(c);
       return p;
   };
}

Yang digunakan seperti ini:

[1,2,3,4,5,6,7].reduce(chunker(3),[]);

Kemudian fungsi yang masih cukup ketat yang melakukan semuanya sekaligus:

function chunk(arr, n) {
    return arr.reduce(function(p, cur, i) {
        (p[i/n|0] = p[i/n|0] || []).push(cur);
        return p;
    },[]);
}

chunk([1,2,3,4,5,6,7], 3);
pengguna239558
sumber
Tidak Bekerja di iE8.
Nadeemmnn Mohd
4
HA! Saya suka komentar kucing. maaf karena tidak ada input konstruktif tambahan :)
29er
Saya akan melakukannya (p[i/n|0] || (p[i/n|0] = [])), jadi Anda tidak menetapkan nilai, jika tidak perlu ...
yckart
12

Saya bertujuan menciptakan solusi non-mutasi sederhana di ES6 murni. Keanehan dalam javascript membuatnya perlu mengisi array kosong sebelum memetakan :-(

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

Versi ini dengan rekursi tampak lebih sederhana dan lebih menarik:

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

Fungsi array ES6 yang sangat lemah menghasilkan puzzle yang bagus :-)

thoredge
sumber
1
Saya juga menulis milik saya seperti ini. Ini masih berfungsi jika Anda menghapus 0dari fill, yang membuat filltampilan sedikit lebih masuk akal, imho.
Coert Grobbelaar
12

Saya pikir ini solusi rekursif yang bagus dengan sintaks 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));

Gergely Fehérvári
sumber
9

Membuat paket npm untuk https://www.npmjs.com/package/array.chunk ini

var result = [];

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

Saat menggunakan TypedArray

var result = [];

for (var i = 0; i < arr.length; i += size) {
  result.push(arr.subarray(i, size + i));
}
return result;
zhiyelee
sumber
@ A1rPun Maaf, saya tidak menambahkan komentar di sana. Ya, tidak ada slicemetode untuk TypedArray, kita dapat menggunakan subarraysebagai gantinya developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
zhiyelee
8

Jika Anda menggunakan versi EcmaScript> = 5.1, Anda dapat mengimplementasikan versi fungsional chunk()menggunakan array.reduce () yang memiliki kompleksitas 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' ] ]

Penjelasan masing // nbr- masing di atas:

  1. Buat potongan baru jika nilai sebelumnya, yaitu susunan potongan yang dikembalikan sebelumnya, kosong atau jika potongan terakhir sebelumnya memiliki chunkSizeitem
  2. Tambahkan potongan baru ke array potongan yang ada
  3. Jika tidak, chunk saat ini adalah chunk terakhir dalam array chunks
  4. Tambahkan nilai saat ini ke chunk
  5. Kembalikan array potongan yang dimodifikasi
  6. Inisialisasi pengurangan dengan melewatkan array kosong

Kari berdasarkan pada chunkSize:

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

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

Anda dapat menambahkan chunk()fungsi ke Arrayobjek global :

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' ] ]

matsev
sumber
7
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 ] ]
Arpit Jain
sumber
a.splice (0, 2) menghilangkan subarray dari [0..1] dari a dan mengembalikan subarray a [0..1]. Saya membuat array dari semua array
Arpit Jain
2
Saya sarankan menggunakan metode slice () non-destructive alih-alih splice ()
Ash Blue
7
results = []
chunk_size = 10
while(array.length > 0){
   results.push(array.splice(0, chunk_size))
}
Jon
sumber
1
Tidak yakin mengapa ini tidak dipilih, tetapi kodenya dapat menggunakan beberapa penjelasan.
jpaugh
2
Karena sambungan merusak ke array asli.
metalim
7

Pendekatan ES2015 berikut berfungsi tanpa harus mendefinisikan fungsi dan langsung pada array anonim (contoh dengan ukuran chunk 2):

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

Jika Anda ingin mendefinisikan fungsi untuk ini, Anda bisa melakukannya sebagai berikut (meningkatkan komentar K ._ pada jawaban Blazemonger ):

const array_chunks = (array, chunk_size) => array
    .map((_, i, all) => all.slice(i*chunk_size, (i+1)*chunk_size))
    .filter(x => x.length)
pengguna1460043
sumber
6

Dan ini akan menjadi kontribusi saya untuk topik ini. Saya kira .reduce()itu cara terbaik.

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

Tetapi implementasi di atas tidak terlalu efisien karena .reduce()dijalankan melalui semua arrfungsi. Pendekatan yang lebih efisien (sangat dekat dengan solusi imperatif tercepat) adalah, mengulangi pengurangan array (yang akan dipotong) karena kita dapat menghitung ukurannya terlebih dahulu Math.ceil(arr/n);. Setelah kita memiliki array hasil kosong seperti Array(Math.ceil(arr.length/n)).fill();yang lain adalah memetakan irisan arrarray ke dalamnya.

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

Redu
sumber
5

Gunakan potongan dari lodash

lodash.chunk(arr,<size>).forEach(chunk=>{
  console.log(chunk);
})
Milind Chaudhary
sumber
5

Satu lagi solusi menggunakan arr.reduce():

const chunk = (arr, size) => (
  arr.reduce((acc, _, i) => {
    if (i % size === 0) acc.push(arr.slice(i, i + size))
    return acc
  }, [])
)

// Usage:
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const chunked = chunk(numbers, 3)
console.log(chunked)

Solusi ini sangat mirip dengan solusi oleh Steve Holgado . Namun, karena solusi ini tidak menggunakan penyebaran array dan tidak membuat array baru dalam fungsi peredam, itu lebih cepat (lihat uji jsPerf ) dan lebih mudah dibaca (sintaksis sederhana) daripada solusi lain.

Pada setiap iterasi ke - n (di mana n = size; mulai dari iterasi pertama), array akumulator ( acc) ditambahkan dengan potongan array ()arr.slice(i, i + size) ) dan kemudian dikembalikan. Di iterasi lain, array akumulator dikembalikan apa adanya.

Jika sizenol, metode mengembalikan array kosong. Jika sizenegatif, metode mengembalikan hasil yang rusak. Jadi, jika diperlukan dalam kasus Anda, Anda mungkin ingin melakukan sesuatu tentang sizenilai - nilai negatif atau non-positif .


Jika kecepatan penting dalam kasus Anda, forloop sederhana akan lebih cepat daripada menggunakan arr.reduce()(lihat tes jsPerf ), dan beberapa mungkin menemukan gaya ini lebih mudah dibaca:

function chunk(arr, size) {
  // This prevents infinite loops
  if (size < 1) throw new Error('Size must be positive')

  const result = []
  for (let i = 0; i < arr.length; i += size) {
    result.push(arr.slice(i, i + size))
  }
  return result
}
mts knn
sumber
4

Untuk solusi fungsional, gunakan Ramda :

Di mana popularProductsarray input Anda, 5adalah ukuran chunk

import splitEvery from 'ramda/src/splitEvery'

splitEvery(5, popularProducts).map((chunk, i) => {
// do something with chunk

})

Damian Green
sumber
4

Pendekatan satu garis ES6 berdasarkan Array.prototype reducedan pushmetode:

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]]
dhilt
sumber
4

Versi ES6 Generator

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);
Rm558
sumber
Gunakan constsebagai gantinya.
Константин Ван
4

Ini adalah solusi paling efisien dan mudah yang dapat saya pikirkan:

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;
}
Mpen
sumber
4

ES6 menyebar fungsional #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]) );

goofballLogic
sumber
4

Berikut adalah solusi rekursif yang mengoptimalkan panggilan ekor.

const splitEvery = (n, xs, y=[]) =>
  xs.length===0 ? y : splitEvery(n, xs.slice(n), y.concat([xs.slice(0, n)])) 

console.log(splitEvery(2, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))

Chris Vouga
sumber
2

EDIT: @ mblase75 menambahkan kode yang lebih ringkas ke jawaban sebelumnya ketika saya menulis milik saya, jadi saya sarankan pergi dengan solusinya.

Anda dapat menggunakan kode seperti ini:

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

Ubah nilai arraySizeuntuk mengubah panjang maksimum array yang lebih kecil.

dentaku
sumber
2

Berikut ini adalah solusi non-mutasi yang hanya menggunakan rekursi dan slice ().

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

Maka cukup gunakan saja splitToChunks([1, 2, 3, 4, 5], 3)untuk mendapatkannya [[1, 2, 3], [4, 5]].

Berikut ini biola untuk Anda coba: https://jsfiddle.net/6wtrbx6k/2/

Suhair Zain
sumber