Chia mảng thành nhiều phần


516

Hãy nói rằng tôi có một mảng Javascript như sau:

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

Cách tiếp cận nào sẽ phù hợp để phân chia (tách) mảng thành nhiều mảng nhỏ hơn, giả sử, tối đa 10 phần tử?




24
Đối với người dùng lodash , bạn đang tìm kiếm _.chunk .
Ulysse BN

2
Tôi vừa thử const chunk = (arr, n) => arr.length ? [arr.slice(0, n), ...chunk(arr.slice(n), n)] : []cái nào đẹp và ngắn nhưng dường như mất khoảng 256 × miễn là câu trả lời của @ AymKdn cho 1.000 yếu tố và 1.058 × miễn là 10.000 yếu tố!
Toph

nếu bạn cũng cần kích thước tối thiểu của đoạn cuối cùng, đây là các tùy chọn: stackoverflow.com/questions/57908133/
Kẻ Ahmet Cetin

Câu trả lời:


640

Các Array.slice phương pháp có thể trích xuất một lát từ đầu, giữa hoặc cuối của một mảng cho bất kỳ mục đích bạn cần, mà không thay đổi mảng gốc.

var i,j,temparray,chunk = 10;
for (i=0,j=array.length; i<j; i+=chunk) {
    temparray = array.slice(i,i+chunk);
    // do whatever
}

19
Hãy nhớ rằng nếu đây là một chức năng util để khẳng định chống lại chunkđược 0. (vòng lặp vô hạn)
Steven Lu

19
Không, phần cuối cùng chỉ nên nhỏ hơn những phần khác.
Blazemonger

7
@Blazemonger, thật đấy! Lần tới tôi sẽ thực sự thử nó trước khi đưa ra kết luận. Tôi đã giả định (không chính xác) rằng việc chuyển một đầu vào vào mảng.slice vượt quá giới hạn của mảng sẽ là một vấn đề, nhưng nó hoạt động hoàn hảo!
rysqui

55
Đối với một lớp lót (những người yêu thích chuỗi) : 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));.
Toàn cảnh

8
Tại sao bạn cần j? Đầu tiên tôi nghĩ nó là một sự tối ưu hóa, nhưng nó thực sự chậm hơn so với (i = 0; i <mảng.length; i ++) {}
Alex

149

Được sửa đổi từ câu trả lời của 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]]


phụ lục nhỏ :

Tôi nên chỉ ra rằng ở trên là một cách giải quyết không thanh lịch (trong tâm trí của tôi) để sử dụng Array.map. Về cơ bản, nó thực hiện như sau, trong đó ~ là ghép:

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

Nó có cùng thời gian chạy tiệm cận như phương pháp bên dưới, nhưng có lẽ yếu tố bất biến tồi tệ hơn do xây dựng danh sách trống. Người ta có thể viết lại như sau (hầu hết giống như phương pháp của Blazemonger, đó là lý do tại sao ban đầu tôi không gửi câu trả lời này):

Phương pháp hiệu quả hơn:

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


Cách ưa thích của tôi ngày nay là ở trên, hoặc một trong những điều sau đây:

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

  }
});

Bản giới thiệu:

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

Hoặc nếu bạn không muốn một hàm Array.range, thì thực tế nó chỉ là một lớp lót (không bao gồm lông tơ):

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

hoặc là

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

41
Ơ, tôi sẽ tránh gây rối với nguyên mẫu vì cảm giác mát mẻ mà bạn có được khi gọi chunkhàm trên mảng không thực sự vượt quá sự phức tạp thêm mà bạn thêm vào và các lỗi tinh vi gây rối với các nguyên mẫu tích hợp có thể gây ra.
Gordon Gustafson

12
Anh ấy không làm phiền họ, anh ấy mở rộng chúng cho Mảng. Tôi hiểu rằng không bao giờ chạm vào Object.prototype bởi vì điều đó sẽ bong bóng cho tất cả các đối tượng (mọi thứ) nhưng đối với chức năng cụ thể của mảng này, tôi không thấy bất kỳ vấn đề nào.
rlemon

Khá chắc chắn rằng sẽ array.map(function(i)không array.map(function(elem,i)mặc dù
Nigel Thiên thần

3
Dựa trên biểu đồ tương thích trên trang web mozilla dev, Array.map cho IE9 +. Hãy cẩn thận.
Maikel D

Hãy cẩn thận để vượt qua - 7,5 loại số - dẫn đến khối không thể đoán trước
Gal Bracha

103

Đây là phiên bản ES6 sử dụng less

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

Và bạn đã sẵn sàng xâu chuỗi các bản đồ / giảm bớt các biến đổi. Mảng đầu vào của bạn được giữ nguyên


Nếu bạn thích phiên bản ngắn hơn nhưng ít đọc hơn, bạn có thể rắc một ít concatvào hỗn hợp để có kết quả cuối cùng:

inputArray.reduce((all,one,i) => {
   const ch = Math.floor(i/perChunk); 
   all[ch] = [].concat((all[ch]||[]),one); 
   return all
}, [])

Đây có vẻ như là giải pháp cô đọng nhất. Chunk Index = Math.floor (index / perChunk) nhận được là gì? Có phải là trung bình?
tôi-tôi

5/2 = 2.5Math.floor(2.5) = 2vì vậy, mục có chỉ số 5 sẽ được đặt trong nhóm 2
Andrei R

Cảm ơn Andrei R. Ah để nó bước qua 0 - 2. Vậy cái này được gọi là gì trong các thuật ngữ toán học? Tôi đoán quan điểm của tôi là tôi sẽ không bao giờ nghĩ sẽ chia chỉ số / 2 cho mỗi chỉ mục để lấy chỉ số của mỗi lát. Vì vậy, tôi đang cố gắng quấn đầu vì nó thực sự thích nó nhưng không hiểu đầy đủ về thuật ngữ Toán học. Tôi thường làm điều này để lấy trung bình của một tổng số nhưng điều này có vẻ khác nhau.
tôi-tôi

Giải pháp này không hiệu quả khi so sánh với các giải pháp khác vì bạn cần lặp lại qua mọi yếu tố.
JP de la Torre

bạn nói đúng @JPdelaTorre, nó có thể không hiệu quả bằng các giải pháp cắt mảng, nhưng bạn đang chia tóc ở đây. Hầu hết các câu trả lời được liệt kê sẽ không hiệu quả theo định nghĩa đó.
Andrei R

102

Cố gắng tránh mucking với các nguyên mẫu gốc, bao gồm Array.prototype, nếu bạn không biết ai sẽ tiêu thụ mã của bạn (bên thứ 3, đồng nghiệp, chính bạn vào một ngày sau đó, v.v.).

Có nhiều cách để mở rộng các nguyên mẫu một cách an toàn (nhưng không phải trong tất cả các trình duyệt) và có những cách để tiêu thụ một cách an toàn các đối tượng được tạo từ các nguyên mẫu mở rộng, nhưng một nguyên tắc tốt hơn là tuân thủ Nguyên tắc tối thiểu bất ngờ và tránh hoàn toàn các thực hành này.

Nếu bạn có thời gian, hãy xem cuộc nói chuyện của Andrew Dupont 2011, "Mọi thứ đều được phép: Mở rộng tích hợp" , để thảo luận tốt về chủ đề này.

Nhưng trở lại câu hỏi, trong khi các giải pháp trên sẽ hoạt động, chúng quá phức tạp và đòi hỏi chi phí tính toán không cần thiết. Đây là giải pháp của tôi:

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;

25
"Tránh mucking với các nguyên mẫu bản địa" các nhà phát triển js mới nên có một hình xăm tạm thời, nếu không vĩnh viễn, của cụm từ này.
Jacob Dalton

2
Tôi đã sử dụng javascript trong nhiều năm và không mất thời gian làm phiền với nguyên mẫu, ở hầu hết các chức năng gọi điện, không bao giờ sửa đổi như bạn thấy một số người làm.
1984

2
gợi ý tốt nhất trong mắt tôi, đơn giản nhất để hiểu và thực hiện, cảm ơn bạn rất nhiều!
Olga Farber

1
@JacobDalton Tôi nghĩ đó là lỗi của tất cả các trường đại học. Mọi người nghĩ rằng OOP phải được sử dụng ở mọi nơi. Vì vậy, họ sợ "chỉ tạo ra một chức năng". Họ muốn chắc chắn để đặt nó bên trong một cái gì đó. Ngay cả khi nó không phù hợp chút nào. Nếu không có ký hiệu dấu chấm thì không có "kiến trúc".
Gherman

51

Tôi đã thử nghiệm các câu trả lời khác nhau vào jsperf.com. Kết quả có sẵn ở đó: https://web.archive.org/web/20150909134228/https://jsperf.com/chunk-mtds

Và chức năng nhanh nhất (và hoạt động từ IE8) là chức năng này:

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

1
Cảm ơn @AymKdn đã thực hiện điểm chuẩn này: Điều này rất hữu ích! Tôi đang sử dụng phương pháp tiếp cận mối nối và nó đã làm sập trình duyệt Chrome v70 của tôi ở kích thước khối 884432. Với cách tiếp cận "lát" được đề xuất của bạn, mã của tôi không còn làm hỏng quá trình "kết xuất" của trình duyệt nữa. :)
Benny Neugebauer

34

Tôi muốn sử dụng phương pháp mối nối :

var chunks = function(array, size) {
  var results = [];
  while (array.length) {
    results.push(array.splice(0, size));
  }
  return results;
};

16
Phải cẩn thận với giải pháp mối nối này vì nó sửa đổi mảng ban đầu, vì vậy hãy chắc chắn ghi lại rõ ràng các tác dụng phụ.
bdrx

3
Sau đó, sử dụng lát thay thế
mplungjan

@mplungjan Kết quả sẽ là cùng một mảng lặp đi lặp lại khi sử dụng lát cắt. Vì vậy, nó không thực sự là một sự thay thế thả trong mà không có một số sửa đổi.
nietonfir

Điều duy nhất mà tôi muốn thêm vào câu trả lời này là một bản sao vào mảng ban đầu. Tôi sẽ làm điều đó với toán tử lây lan của ES6. var clone = [...array]sau đó thực hiện kiểm tra chiều dài và nối trên mảng nhân bản đó.
MauricioLeal

1
Hoặc nếu bạn không thể sử dụng các tính năng ES6, bạn có thể chỉ cần array = array.slice()tạo một bản sao nông.
3limin4t0r

34

Một lớp lót trong 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))

9
nó sửa đổi listmảng ban đầu
Jacka

6
Khắc phục dễ dàng bằng cách sử dụng .slice () .. .map((_,i) => list.slice(i*chuckSize,i*chuckSize+chuckSize))
James Robey

2
Trên JSPerf, điều này thực sự hiệu quả hơn nhiều câu trả lời khác.
Micah Henning

30

Câu hỏi cũ: Câu trả lời mới! Tôi thực sự đã làm việc với một câu trả lời từ câu hỏi này và có một người bạn cải thiện nó! Vì vậy, đây là:

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

14
fyi, hiệu suất của phương thức này là O (N ^ 2), vì vậy không nên sử dụng nó trong các phần mã quan trọng về hiệu năng hoặc với các mảng dài (cụ thể, khi mảng .lengthlớn hơn nhiều so với kích thước khối n). Nếu đây là một ngôn ngữ lười biếng (không giống như javascript), thuật toán này sẽ không bị thời gian O (N ^ 2). Điều đó nói rằng, việc thực hiện đệ quy là thanh lịch. Bạn có thể sửa đổi nó để cải thiện hiệu suất bằng cách trước tiên xác định chức năng của trình trợ giúp lặp lại array,position, sau đó gửi đi: Array.prototype.chunktrả về [hàm trợ giúp của bạn] (...)
ninjagecko

cảm ơn Sensai vì đã ban phước cho tôi với tinh thần của bạn mà tôi đã phải thốt lên tối nay
cắn

1
hoặc ...var chunk = (arr, n) => { if ( !arr.length ) return []; return [ arr.slice( 0, n ) ].concat( chunk(arr.slice(n), n) ) }
Ed Williams

28

Ngày nay, bạn có thể sử dụng chức năng chunk của lodash để chia mảng thành các mảng nhỏ hơn https://lodash.com/docs#chunk Không cần phải loay hoay với các vòng lặp nữa!


3
Tôi cảm thấy nên từ chối các câu hỏi javascript: bạn đã thử dùng lodash chưa? Khá nhiều thứ đầu tiên tôi đưa vào nút hoặc trình duyệt.
Jacob Dalton

20

Đã có nhiều câu trả lời nhưng đây là những gì tôi sử dụng:

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

Đầu tiên, kiểm tra phần còn lại khi chia chỉ số cho kích thước khối.

Nếu có một phần còn lại thì chỉ cần trả về mảng tích lũy.

Nếu không có phần còn lại thì chỉ mục chia hết cho kích thước khối, vì vậy hãy lấy một lát từ mảng ban đầu (bắt đầu từ chỉ mục hiện tại) và thêm nó vào mảng tích lũy.

Vì vậy, mảng tích lũy được trả về cho mỗi lần lặp giảm trông giống như thế này:

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

Giải pháp tốt đẹp và đại diện trực quan tốt đẹp của các lần lặp. Tôi đã kết thúc với một giải pháp rất giống mà tôi đã đăng lên như một câu trả lời: stackoverflow.com/a/60779547
mts knn

15

Sử dụng máy phát điện

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


3
Tôi đã ngạc nhiên với tất cả các câu trả lời cho câu hỏi này gần như sử dụng máy phát điện hoặc sử dụng chúng theo những cách phức tạp hơn. Đẹp ngắn gọn và hiệu suất với giải pháp này.
Keith

14

Ok, hãy bắt đầu với một cái khá chặt chẽ:

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

Được sử dụng như thế này:

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

Sau đó, chúng ta có chức năng giảm chặt chẽ này:

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

Được sử dụng như thế này:

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

Vì một con mèo con chết khi chúng ta liên kết thisvới một số, thay vào đó chúng ta có thể làm cà ri bằng tay như thế này:

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

Được sử dụng như thế này:

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

Sau đó, chức năng vẫn còn khá chặt chẽ mà thực hiện tất cả trong một lần:

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

Không hoạt động trong iE8.
Nadeemmnn Mohd

4
HẠ! Tôi thích bình luận của mèo con. xin lỗi vì không có thêm đầu vào mang tính xây dựng :)
29er

Tôi sẽ làm (p[i/n|0] || (p[i/n|0] = [])), vì vậy bạn không chỉ định một giá trị, nếu không cần thiết ...
yckart

12

Tôi nhằm mục đích tạo ra một giải pháp không đột biến đơn giản trong ES6 thuần túy. Đặc thù trong javascript khiến bạn cần phải điền vào mảng trống trước khi ánh xạ :-(

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

Phiên bản này với đệ quy có vẻ đơn giản và hấp dẫn hơn:

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

Các chức năng mảng cực kỳ yếu của ES6 tạo ra các câu đố hay :-)


1
Tôi cũng đã viết của tôi rất nhiều như thế này. Nó vẫn hoạt động nếu bạn loại bỏ 0khỏi fill, điều này làm cho fillcái nhìn hợp lý hơn một chút, imho.
Coert Grobbelaar

12

Tôi nghĩ rằng đây là một giải pháp đệ quy tốt đẹp với cú pháp 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));


9

Đã tạo gói npm cho https://www.npmjs.com/package/array.chunk này

var result = [];

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

Khi sử dụng TypedArray

var result = [];

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

@ A1rPun Xấu quá, tôi không thêm bình luận ở đó. Phải, không có slicephương pháp nào TypedArray, chúng ta có thể sử dụng subarraythay cho developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
Kẻ

8

Nếu bạn sử dụng phiên bản EcmaScript> = 5.1, bạn có thể triển khai phiên bản chức năng chunk()sử dụng mảng.reduce () có độ phức tạp 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' ] ]

Giải thích của từng // nbrở trên:

  1. Tạo một đoạn mới nếu giá trị trước đó, tức là mảng khối được trả về trước đó, trống hoặc nếu đoạn trước đó có chunkSizecác mục
  2. Thêm đoạn mới vào mảng khối hiện có
  3. Mặt khác, đoạn hiện tại là đoạn cuối cùng trong mảng khối
  4. Thêm giá trị hiện tại vào khối
  5. Trả về mảng đã sửa đổi
  6. Khởi tạo giảm bằng cách chuyển một mảng trống

Currying dựa trên chunkSize:

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

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

Bạn có thể thêm chunk()chức năng vào Arrayđối tượng toàn cầu :

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


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

a.splice (0, 2) loại bỏ phân đoạn con của [0..1] khỏi a và trả về phân đoạn a [0..1]. Tôi đang tạo ra một mảng của tất cả các mảng đó
Arpit Jain

2
Tôi khuyên bạn nên sử dụng phương thức lát () không phá hủy thay vì splice ()
Ash Blue

7
results = []
chunk_size = 10
while(array.length > 0){
   results.push(array.splice(0, chunk_size))
}

1
Không chắc chắn tại sao điều này đã được bỏ phiếu, nhưng mã có thể sử dụng một số giải thích.
jpaugh

2
Bởi vì mối nối có tính phá hủy đối với mảng ban đầu.
metalim

7

Cách tiếp cận ES2015 sau đây hoạt động mà không phải xác định hàm và trực tiếp trên mảng ẩn danh (ví dụ với kích thước khối 2):

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

Nếu bạn muốn xác định một chức năng cho việc này, bạn có thể thực hiện như sau (cải thiện nhận xét của K ._ về câu trả lời của Blazemonger ):

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

6

Và đây sẽ là đóng góp của tôi cho chủ đề này. Tôi đoán .reduce()là cách tốt nhất.

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

Nhưng việc thực hiện ở trên không hiệu quả lắm vì .reduce()chạy qua tất cả các arrchức năng. Một cách tiếp cận hiệu quả hơn (rất gần với giải pháp bắt buộc nhanh nhất) sẽ là, lặp đi lặp lại trên mảng đã giảm (sẽ bị chunk) vì chúng ta có thể tính toán kích thước của nó trước Math.ceil(arr/n);. Một khi chúng ta có mảng kết quả trống như Array(Math.ceil(arr.length/n)).fill();phần còn lại là ánh xạ các lát của arrmảng vào nó.

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


5

Sử dụng chunk từ lodash

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

5

Thêm một giải pháp sử dụng 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)

Giải pháp này rất giống với giải pháp của Steve Holgado . Tuy nhiên, vì giải pháp này không sử dụng trải rộng mảng và không tạo ra các mảng mới trong chức năng giảm tốc, nên nó nhanh hơn (xem thử nghiệm jsPerf ) và chủ quan dễ đọc hơn (cú pháp đơn giản hơn) so với giải pháp khác.

Ở mỗi lần lặp thứ n (trong đó n = size; bắt đầu từ lần lặp đầu tiên), mảng tích lũy ( acc) được nối với một đoạn của mảng (arr.slice(i, i + size) ) và sau đó được trả về. Ở các lần lặp khác, mảng tích lũy được trả về nguyên trạng.

Nếu sizebằng 0, phương thức trả về một mảng trống. Nếu sizelà âm, phương thức trả về kết quả bị hỏng. Vì vậy, nếu cần trong trường hợp của bạn, bạn có thể muốn làm gì đó về sizecác giá trị âm hoặc không tích cực .


Nếu tốc độ là quan trọng trong trường hợp của bạn, một forvòng lặp đơn giản sẽ nhanh hơn so với sử dụng arr.reduce()(xem thử nghiệm jsPerf ) và một số có thể thấy phong cách này cũng dễ đọc hơn:

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
}

4

Đối với một giải pháp chức năng, sử dụng Ramda :

popularProductsMảng đầu vào của bạn ở đâu , 5là kích thước khối

import splitEvery from 'ramda/src/splitEvery'

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

})


4

Cách tiếp cận một dòng ES6 dựa trên Array.prototype reducepushphương pháp:

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

4

Phiên bản máy phát điện 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);

Sử dụng constthay thế.
Toàn cảnh

4

Đây là giải pháp hiệu quả và đơn giản nhất mà tôi có thể nghĩ ra:

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

4

ES6 lây lan chức năng #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]) );


4

Đây là một giải pháp đệ quy được tối ưu hóa cuộc gọi đuôi.

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


2

EDIT: @ mblase75 đã thêm mã ngắn gọn hơn vào câu trả lời trước đó trong khi tôi đang viết của tôi, vì vậy tôi khuyên bạn nên đi với giải pháp của mình.

Bạn có thể sử dụng mã như thế này:

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

Thay đổi giá trị của arraySizeđể thay đổi độ dài tối đa của các mảng nhỏ hơn.


2

Đây là một giải pháp không đột biến chỉ sử dụng đệ quy và lát ().

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

Sau đó, chỉ cần sử dụng nó như muốn splitToChunks([1, 2, 3, 4, 5], 3)có được [[1, 2, 3], [4, 5]].

Dưới đây là một mẹo để bạn thử: https://jsfiddle.net/6wtrbx6k/2/

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.