使用 Lodash 分块分割 JavaScript 数组

IT技术 javascript split functional-programming underscore.js lodash
2021-01-22 10:37:05

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

例如:给定这个数组

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

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

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

我知道针对这个问题的纯 JavaScript解决方案,但由于我已经在使用Lodash,我想知道 Lodash 是否为此提供了更好的解决方案。

编辑:

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

5个回答

看看 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 和 underscore 这两个向后兼容的 API 会很有帮助
2021-03-26 10:37:05
@Jonah 是的。以前的答案不再是最好的答案,因此为了读者,我更新了已接受的答案:)
2021-04-04 10:37:05

对于基于下划线的解决方案,试试这个:

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();
虽然我完全赞成将 Underscore 用于它最擅长的事情(并且 OP 要求使用基于 Underscore 的解决方案,因此不是不值得的)和功能解决方案,但似乎这个解决方案引入了大量开销。正如@ajax33321 指出的那样,splice在循环中仍然是三行,而且我猜,性能更高。如果您的数组很短,这可能无关紧要,但如果您要处理成百上千个项目,请务必注意其性能。
2021-03-16 10:37:05
这不再是最好的解决方案。请改用chunk()
2021-03-22 10:37:05
奇怪的是,UnderscoregroupBy 返回的是一个 object,而不是一个数组。不是破坏者——你得到基本相同的功能——但语义有点奇怪。编辑:哦,它这样做是为了保持可链接性。还是挺有意思的。
2021-03-30 10:37:05
@Cesar Canassa:为了将来阅读该代码的开发人员,如果您经常使用它,请考虑将其作为一个函数放入自定义库中,或者如果您不会使用它,请对其进行良好的评论:)
2021-04-07 10:37:05
@乔丹:没有意识到这一点。编辑了将对象转换为数组的答案。
2021-04-08 10:37:05

一个可能更简单的表达:

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>

比什么简单?答案应该是独立的。
2021-04-04 10:37:05

Underscore从版本 1.9.0 开始支持_.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>

试试这个更实用(例如,如果您想根据要在每个子数组中作为容器的项目数量来拆分数组):

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恕我直言,参数并不实用。你通常不想通过它;但您始终需要指定块大小。最好交换这两个参数。
2021-03-20 10:37:05
为什么这是一个do while循环?没有人想要得到空块。
2021-03-26 10:37:05