Javascript 将数组拆分为块
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8495687/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Split array into chunks
提问by Industrial
Let's say that I have an Javascript array looking as following:
假设我有一个 Javascript 数组,如下所示:
["Element 1","Element 2","Element 3",...]; // with close to a hundred elements.
What approach would be appropriate to chunk (split) the array into many smaller arrays with, lets say, 10 elements at its most?
什么方法适合将数组分块(拆分)为许多更小的数组,例如最多 10 个元素?
回答by Blazemonger
The array.slicemethod can extract a slice from the beginning, middle, or end of an array for whatever purposes you require, without changing the original array.
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
}
回答by ninjagecko
Modified from an answer by dbaseman: https://stackoverflow.com/a/10456344/711085
修改自 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]]
minor addendum:
次要附录:
I should point out that the above is a not-that-elegant (in my mind) workaround to use Array.map
. It basically does the following, where ~ is concatenation:
我应该指出,以上是使用Array.map
. 它基本上执行以下操作,其中 ~ 是连接:
[[1,2,3]]~[]~[]~[] ~ [[4,5,6]]~[]~[]~[] ~ [[7]]
It has the same asymptotic running time as the method below, but perhaps a worse constant factor due to building empty lists. One could rewrite this as follows (mostly the same as Blazemonger's method, which is why I did not originally submit this answer):
它与下面的方法具有相同的渐近运行时间,但由于构建空列表,它可能是一个更糟糕的常数因子。可以将其重写如下(主要与 Blazemonger 的方法相同,这就是我最初没有提交此答案的原因):
More efficient method:
更有效的方法:
// 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)
)
My preferred way nowadays is the above, or one of the following:
我现在首选的方法是上述方法,或以下方法之一:
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]]
Or if you don't want an Array.range function, it's actually just a one-liner (excluding the fluff):
或者如果你不想要一个 Array.range 函数,它实际上只是一个单行(不包括绒毛):
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));
}});
or
或者
Object.defineProperty(Array.prototype, 'chunk', {value: function(n) {
return Array.from(Array(ceil(this.length/n)), (_,i)=>this.slice(i*n,i*n+n));
}});
回答by furf
Try to avoid mucking with native prototypes, including Array.prototype, if you don't know who will be consuming your code (3rd parties, coworkers, yourself at a later date, etc.).
如果您不知道谁将使用您的代码(第 3 方、同事、以后的您自己等),请尽量避免使用本机原型,包括 Array.prototype。
There are ways to safely extend prototypes (but not in all browsers) and there are ways to safely consume objects created from extended prototypes, but a better rule of thumb is to follow the Principle of Least Surpriseand avoid these practices altogether.
有一些方法可以安全地扩展原型(但不是在所有浏览器中),也有一些方法可以安全地使用从扩展原型创建的对象,但更好的经验法则是遵循最小意外原则并完全避免这些做法。
If you have some time, watch Andrew Dupont's JSConf 2011 talk, "Everything is Permitted: Extending Built-ins", for a good discussion about this topic.
如果您有时间,请观看 Andrew Dupont 的 JSConf 2011 演讲“一切都是允许的:扩展内置函数”,以获得关于该主题的精彩讨论。
But back to the question, while the solutions above will work, they are overly complex and requiring unnecessary computational overhead. Here is my solution:
但回到问题,虽然上述解决方案可行,但它们过于复杂并且需要不必要的计算开销。这是我的解决方案:
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;
回答by Andrei R
Here's a ES6 version using reduce
这是使用 reduce 的 ES6 版本
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']]
And you're ready to chain further map/reduce transformations. Your input array is left intact
并且您已准备好链接进一步的 map/reduce 转换。您的输入数组保持不变
If you prefer a shorter but less readable version, you can sprinkle some concat
into the mix for the same end result:
如果您更喜欢较短但可读性较差的版本,您可以concat
在混合中加入一些以获得相同的最终结果:
inputArray.reduce((all,one,i) => {
const ch = Math.floor(i/perChunk);
all[ch] = [].concat((all[ch]||[]),one);
return all
}, [])
回答by AymKdn
I tested the different answers into jsperf.com. The result is available there: https://web.archive.org/web/20150909134228/https://jsperf.com/chunk-mtds
我在 jsperf.com 中测试了不同的答案。结果在那里可用:https: //web.archive.org/web/20150909134228/https: //jsperf.com/chunk-mtds
And the fastest function (and that works from IE8) is this one:
最快的功能(适用于 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;
}
回答by Arek Flinik
回答by Shairon Toledo
One-liner in ECMA 6
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))
回答by rlemon
Old question: New answer! I actually was working with an answer from this question and had a friend improve on it! So here it is:
老问题:新答案!我实际上正在研究这个问题的答案,并让朋友改进了它!所以这里是:
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]]
回答by George Herolyants
Nowadays you can use lodash' chunk function to split the array into smaller arrays https://lodash.com/docs#chunkNo need to fiddle with the loops anymore!
现在你可以使用 lodash 的 chunk 函数将数组拆分成更小的数组https://lodash.com/docs#chunk不再需要摆弄循环了!
回答by Steve Holgado
There have been many answers but this is what I use:
有很多答案,但这就是我使用的:
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]]
First, check for a remainder when dividing the index by the chunk size.
首先,在将索引除以块大小时检查余数。
If there is a remainder then just return the accumulator array.
如果有余数,则只返回累加器数组。
If there is no remainder then the index is divisible by the chunk size, so take a slice from the original array (starting at the current index) and add it to the accumulator array.
如果没有余数,则索引可被块大小整除,因此从原始数组(从当前索引开始)中取出一个切片并将其添加到累加器数组中。
So, the returned accumulator array for each iteration of reduce looks something like this:
因此,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]]