使用Lodash将JavaScript数组拆分为多个块


83

我需要将一个JavaScript数组拆分成多个n大小的块。

例如:鉴于此数组

["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"]

n等于4,输出应该是这样的:

[ ["a1", "a2", "a3", "a4"],
  ["a5", "a6", "a7", "a8"],
  ["a9", "a10", "a11", "a12"],
  ["a13"]
]

我知道有解决此问题的纯JavaScript解决方案,但是由于我已经在使用Lodash,所以我想知道Lodash是否可以为此提供更好的解决方案。

编辑:

我创建了一个jsPerf测试来检查下划线解决方案的速度。

Answers:


125

看看lodash的https : //lodash.com/docs#chunk

const data = ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"];
const chunks = _.chunk(data, 3);
console.log(chunks);
// [
//  ["a1", "a2", "a3"],
//  ["a4", "a5", "a6"],
//  ["a7", "a8", "a9"],
//  ["a10", "a11", "a12"],
//  ["a13"]
// ]
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>


如果lodash和下划线都向后兼容的API,将会很有帮助
Jonno_FTW

@Jonah是的。先前的答案不再是最佳答案,因此为了读者的缘故,我更新了接受的答案:)
Cesar Canassa,2017年

90

对于基于Underscore的解决方案,请尝试以下操作:

var data = ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"];
var n = 3;
var lists = _.groupBy(data, function(element, index){
  return Math.floor(index/n);
});
lists = _.toArray(lists); //Added this to convert the returned object to an array.
console.log(lists);

使用链包装器方法,您可以将以下两个语句组合在一起:

var data = ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"];
var n = 3;
var lists = _.chain(data).groupBy(function(element, index){
  return Math.floor(index/n);
}).toArray()
.value();

1
奇怪的是,UnderscoregroupBy 返回的是对象,而不是数组。不是破坏者-您获得的功能基本相同-但语义有些奇怪。编辑:哦,这样做是为了保持可链接性。仍然很有趣。
乔丹

@Cesar Canassa:为了将来阅读该代码的开发人员,如果您会
经常

@乔丹:没意识到。编辑答案以将对象转换为数组。
昌都

尽管我全力以赴地使用Underscore来完成其最出色的工作(OP要求基于Underscore的解决方案,所以并非应有),但对于功能性解决方案,似乎此解决方案会带来大量开销。正如@ ajax33321所指出的,splice循环中仍然是三层结构,而且我猜想它的性能更高。如果数组很短,可能没关系,但是如果要处理成百上千个项目,请注意其性能。
乔丹

1
这不再是最佳解决方案。请改为使用chunk()
乔纳

4

一个可能更简单的表达式:

const coll = [ "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9" ];
const n = 2;
const chunks = _.range(coll.length / n).map(i => coll.slice(i * n, (i + 1) * n));
console.log(chunks);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>


1
比什么还简单?答案应该独立存在。
内森·塔吉

4

从1.9.0版开始,Underscore原生支持_.chunk()

const data = ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"];
const chunks = _.chunk(data, 4);
console.log(chunks);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore.js"></script>


1

尝试使用此方法更实用(例如,如果您要根据要在每个子数组中容纳的项目数量拆分数组):

function chunk(arr, start, amount){
    var result = [], 
        i, 
        start = start || 0, 
        amount = amount || 500, 
        len = arr.length;

    do {
        //console.log('appending ', start, '-', start + amount, 'of ', len, '.');
        result.push(arr.slice(start, start+amount));
        start += amount;

    } while (start< len);

    return result;
};

以及您的情况下的用法:

var arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],
    chunked = chunk(arr, 0, Math.floor(arr.length/3)); //to get 4 nested arrays

console.log(chunked);

还有一种情况:

var arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],
    chunked = chunk(arr, 0, 3); // to get 6 nested arrays each containing maximum of 3 items

console.log(chunked);

start参数并不是真正实用的恕我直言。您通常不希望通过它。但您始终需要指定块大小。最好交换这两个参数。
Bergi 2015年

为什么这是一个do while循环?没有人想得到空块。
Bergi 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.