假设我有一个如下所示的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个元素?
EDIT: @mblase75 added more concise code to the earlier answer while I was writing mine, so I recommend going with his solution.
You could use code like this:
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));
}
Change the value of arraySize
to change the maximum length of the smaller arrays.
Here is a non-mutating solution using only recursion and slice().
const splitToChunks = (arr, chunkSize, acc = []) => (
arr.length > chunkSize ?
splitToChunks(
arr.slice(chunkSize),
chunkSize,
[...acc, arr.slice(0, chunkSize)]
) :
[...acc, arr]
);
Then simply use it like splitToChunks([1, 2, 3, 4, 5], 3)
to get [[1, 2, 3], [4, 5]]
.
Here is a fiddle for you to try out: https://jsfiddle.net/6wtrbx6k/2/
Use chunk from lodash
lodash.chunk(arr,<size>).forEach(chunk=>{
console.log(chunk);
})
ES6 spreads functional #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]) );
This is the most efficient and straight-forward solution I could think of:
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;
}
ES6 one-line approach based on Array.prototype
reduce
and push
methods:
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]]
以下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)
ES6 Generator version
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);
results = []
chunk_size = 10
while(array.length > 0){
results.push(array.splice(0, chunk_size))
}
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 ] ]
为此https://www.npmjs.com/package/array.chunk创建了一个npm包
var result = [];
for (var i = 0; i < arr.length; i += size) {
result.push(arr.slice(i, size + i));
}
return result;
var result = [];
for (var i = 0; i < arr.length; i += size) {
result.push(arr.subarray(i, size + i));
}
return result;
我认为这是使用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));
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]]
我的目标是在纯ES6中创建一个简单的非变异解决方案。javascript中的特殊性使得有必要在映射前填充空数组:-(
function chunk(a, l) {
return new Array(Math.ceil(a.length / l)).fill(0)
.map((_, n) => a.slice(n*l, n*l + l));
}
这个带有递归的版本看起来更简单,更引人注目:
function chunk(a, l) {
if (a.length == 0) return [];
else return [a.slice(0, l)].concat(chunk(a.slice(l), l));
}
ES6的荒谬的数组功能令人困惑:-)
有很多答案,但这是我使用的:
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]]
首先,检查索引除以块大小时是否有余数。
如果还有余数,则只返回累加器数组。
如果没有余数,则索引可以被块大小整除,因此从原始数组中获取一个切片(从当前索引开始),然后将其添加到累加器数组中。
因此,针对reduce的每次迭代返回的累加器数组如下所示:
// 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]]
好吧,让我们从一个相当紧的开始:
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); });
}
像这样使用:
chunk([1,2,3,4,5,6,7], 2);
然后我们有这个紧密的reducer函数:
function chunker(p, c, i) {
(p[i/this|0] = p[i/this|0] || []).push(c);
return p;
}
像这样使用:
[1,2,3,4,5,6,7].reduce(chunker.bind(3),[]);
由于小猫绑定this
到数字时会死亡,因此我们可以像这样手动手动计算:
// 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;
};
}
像这样使用:
[1,2,3,4,5,6,7].reduce(chunker(3),[]);
然后,仍然非常紧凑的功能可以一次性完成所有工作:
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);
如今,您可以使用lodash的块函数将数组拆分为更小的数组https://lodash.com/docs#chunk不再需要弄乱循环了!
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))
我更喜欢使用拼接方法:
var chunks = function(array, size) {
var results = [];
while (array.length) {
results.push(array.splice(0, size));
}
return results;
};
旧问题:新答案!实际上,我正在研究此问题的答案,并且有一位朋友对此进行了改进!所以这里是:
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]]
我在jsperf.com中测试了不同的答案。结果在此处可用:https : //web.archive.org/web/20150909134228/https : //jsperf.com/chunk-mtds
最快的功能(可从IE8使用)是这一功能:
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;
}
如果您不知道谁在使用您的代码(第三方,同事,您自己等),请尝试避免与原生原型(包括Array.prototype)混为一谈。
有一些方法可以安全地扩展原型(但不是在所有浏览器中),并且可以安全地使用从扩展的原型创建的对象,但是更好的经验法则是遵循“最不惊奇原则”并完全避免这些做法。
如果您有时间,请观看Andrew Dupont在JSConf 2011上的演讲“一切都允许:扩展内置插件”,以获取有关此主题的精彩讨论。
但是回到问题所在,尽管上述解决方案可以工作,但它们过于复杂,需要不必要的计算开销。这是我的解决方案:
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;
该array.slice方法可以从一开始,中间,或自己需要的任何目的数组的结束提取切片,在不改变原来的数组。
var i,j,temparray,chunk = 10;
for (i=0,j=array.length; i<j; i+=chunk) {
temparray = array.slice(i,i+chunk);
// do whatever
}
Here is neat & optimised implemention of
chunk()
function. Assuming default chunk size is10
.