假设我有一个 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 个元素?
array.slice方法可以根据需要从数组的开头、中间或结尾提取切片,而无需更改原始数组。
var i,j, temporary, chunk = 10;
for (i = 0,j = array.length; i < j; i += chunk) {
temporary = array.slice(i, i + chunk);
// do whatever
}
这是使用 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']]
并且您已准备好链接进一步的 map/reduce 转换。您的输入数组保持不变
如果您更喜欢较短但可读性较差的版本,您可以concat
在混合物中加入一些以获得相同的最终结果:
inputArray.reduce((all,one,i) => {
const ch = Math.floor(i/perChunk);
all[ch] = [].concat((all[ch]||[]),one);
return all
}, [])
您可以使用余数运算符将连续的项目放入不同的块中:
const ch = (i % perChunk);
修改自 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]]
次要附录:
我应该指出,以上是使用Array.map
. 它基本上执行以下操作,其中 ~ 是连接:
[[1,2,3]]~[]~[]~[] ~ [[4,5,6]]~[]~[]~[] ~ [[7]]
它与下面的方法具有相同的渐近运行时间,但由于构建空列表,它可能是一个更糟糕的常数因子。可以将其重写如下(主要与 Blazemonger 的方法相同,这就是我最初没有提交此答案的原因):
更有效的方法:
// 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)
)
我现在首选的方法是上述方法,或以下方法之一:
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));
}
});
演示:
> JSON.stringify( Array.range(10).chunk(3) );
[[1,2,3],[4,5,6],[7,8,9],[10]]
或者如果你不想要一个 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));
}});
或者
Object.defineProperty(Array.prototype, 'chunk', {value: function(n) {
return Array.from(Array(ceil(this.length/n)), (_,i)=>this.slice(i*n,i*n+n));
}});
Array.prototype
如果您不知道谁将使用您的代码(第 3 方、同事、以后的您自己等),请尽量避免使用本机原型,包括。
有一些方法可以安全地扩展原型(但不是在所有浏览器中),也有一些方法可以安全地使用从扩展原型创建的对象,但更好的经验法则是遵循最小意外原则并完全避免这些做法。
如果您有时间,请观看 Andrew Dupont 在 2011 年的 JSConf 演讲“一切都是允许的:扩展内置函数”,以获得关于这个主题的很好的讨论。
但回到问题,虽然上述解决方案可行,但它们过于复杂并且需要不必要的计算开销。这是我的解决方案:
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;
我在 jsperf.com 中测试了不同的答案。结果在那里可用:https : //web.archive.org/web/20150909134228/https : //jsperf.com/chunk-mtds
最快的功能(适用于 IE8)是这个:
function chunk(arr, chunkSize) {
if (chunkSize <= 0) throw "Invalid chunk size";
var R = [];
for (var i=0,len=arr.length; i<len; i+=chunkSize)
R.push(arr.slice(i,i+chunkSize));
return R;
}