让我们说我有一个Javascript数组看起来如下:
["Element 1","Element 2","Element 3",...]; // with close to a hundred elements.
什么样的方法适合将数组分成许多更小的数组,假设最多有10个元素?
让我们说我有一个Javascript数组看起来如下:
["Element 1","Element 2","Element 3",...]; // with close to a hundred elements.
什么样的方法适合将数组分成许多更小的数组,假设最多有10个元素?
当前回答
我只是在groupBy函数的帮助下写了这个。
// utils const group = (source) => ({ by: (grouping) => { const groups = source.reduce((accumulator, item) => { const name = JSON.stringify(grouping(item)); accumulator[name] = accumulator[name] || []; accumulator[name].push(item); return accumulator; }, {}); return Object.keys(groups).map(key => groups[key]); } }); const chunk = (source, size) => group(source.map((item, index) => ({ item, index }))) .by(x => Math.floor(x.index / size)) .map(x => x.map(v => v.item)); // 103 items const arr = [6,2,6,6,0,7,4,9,3,1,9,6,1,2,7,8,3,3,4,6,8,7,6,9,3,6,3,5,0,9,3,7,0,4,1,9,7,5,7,4,3,4,8,9,0,5,1,0,0,8,0,5,8,3,2,5,6,9,0,0,1,5,1,7,0,6,1,6,8,4,9,8,9,1,6,5,4,9,1,6,6,1,8,3,5,5,7,0,8,3,1,7,1,1,7,6,4,9,7,0,5,1,0]; const chunks = chunk(arr, 10); console.log(JSON.stringify(chunks));
其他回答
这应该是一个简单的答案,没有太多的数学复杂性。
function chunkArray(array, sizeOfTheChunkedArray) {
const chunked = [];
for (let element of array) {
const last = chunked[chunked.length - 1];
if(!last || last.length === sizeOfTheChunkedArray) {
chunked.push([element])
} else {
last.push(element);
}
}
return chunked;
}
迟到了,这是我的意见。就像很多人说的,我首先会想到的是
chunker = (a,n) => [...Array(Math.ceil(a.length/n))].map((v,i) => a.slice(i*n, (i+1)*n))
但我更喜欢但还没看到的是:
chunker = (n) => (r,v,i) => (c = Math.floor(i/n), (r[c] = r[c] || []).push(v), r)
console.log(arr.reduce(chunker(3), []))
有更长的变体
chunker = (a, n) => a.reduce((r,v,i) => {
c = Math.floor(i/n); // which chunk it belongs to
(r[c] = r[c] || []).push(v)
return r
}, [])
console.log(chunker(arr, 3))
解释
常见的答案将首先确定块的数量,然后根据块所在的位置和每个块的大小获得原始数组的切片 块减速器函数将遍历每个元素,并将其放入相应评估的块数组中。
性能几乎相同,据我所见,reduce方法平均慢了4%。
PS: reduce(ing)的优点是很容易改变分组标准。在问题和例子中,标准是相邻的单元格(映射使用切片)。但是你可能想要在“循环”中做它,例如,使用mod (% operator),或任何其他数学公式
重新阅读它让我发现这个公式也可以是一个参数,导致一个更通用的解决方案,需要2个函数来实现答案:
splitter = (a, f) => a.reduce((r,v,i) => { // math formula and/or function
c = f(v, i) || 0; // custom formula, receiving each value and index
(r[c] = r[c] || []).push(v)
return r
}, [])
chunker = (a, n) => splitter(a, (v,i) => Math.floor(i/n))
console.log(chunker(arr, 3))
console.log(splitter(arr, (v,i) => v % 2)) // is it even or odd?
splitter也可以用于创建命名数组,也就是对象,函数返回字符串而不是数字:)
使用来自lodash的chunk
lodash.chunk(arr,<size>).forEach(chunk=>{
console.log(chunk);
})
编辑:@mblase75在我写我的答案时在前面的答案上添加了更简洁的代码,所以我建议使用他的解决方案。
你可以使用这样的代码:
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));
}
修改arraySize的值可以改变较小数组的最大长度。
下面的ES2015方法不需要定义函数,直接在匿名数组上工作(例如块大小为2):
[11,22,33,44,55].map((_, i, all) => all.slice(2*i, 2*i+2)).filter(x=>x.length)
如果你想为此定义一个函数,你可以这样做(改进K._对Blazemonger的回答的评论):
const array_chunks = (array, chunk_size) => array
.map((_, i, all) => all.slice(i*chunk_size, (i+1)*chunk_size))
.filter(x => x.length)