将一个JS数组拆分为N个数组

122

假设我有这样一个JS数组:

var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];

我想要的是将该数组分成N个较小的数组。例如:

split_list_in_n(a, 2)
[[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11]]

For N = 3:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11]]

For N = 4:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11]]

For N = 5:
[[1, 2, 3], [4, 5], [6, 7], [8, 9], [10, 11]]

对于Python,我有这样一个代码:

def split_list_in_n(l, cols):
    """ Split up a list in n lists evenly size chuncks """
    start = 0
    for i in xrange(cols):
        stop = start + len(l[i::cols])
        yield l[start:stop]
        start = stop

对于JS而言,我能想到的最好的右解决方案是一个递归函数,但我不喜欢它,因为它很复杂且难看。这个内部函数返回一个像这样的数组[1, 2, 3, null, 4, 5, 6, null, 7, 8],然后我必须再次循环并手动拆分它。(我的第一次尝试返回了这个:[1, 2, 3, [4, 5, 6, [7, 8, 9]]],然后我决定用null作为分隔符来实现它)。

function split(array, cols) {
    if (cols==1) return array;
    var size = Math.ceil(array.length / cols);
    return array.slice(0, size).concat([null]).concat(split(array.slice(size), cols-1));
}

这是一个 jsfiddle 的链接:http://jsfiddle.net/uduhH/

你怎么实现这个?谢谢!


2
与 - https://dev59.com/cpvga4cB1Zd3GeqP7tGI 相关 - vsync
1
你的 split 函数已经很接近了。你可以通过添加两个数组包装器来消除 null 的问题:if (cols == 1) return [array]return [array.slice(0, size)].concat(split(array.slice(size), cols-1))。我发现这个递归版本比这里大多数答案更易读。 - Scott Sauyet
25个回答

0

我是这样做的,它可以正常工作...

function splitArray(array, parts) {
    if (parts< array.length && array.length > 1 && array != null) {
        var newArray = [];
        var counter1 = 0;
        var counter2 = 0;

        while (counter1 < parts) {
            newArray.push([]);
            counter1 += 1;
        }

        for (var i = 0; i < array.length; i++) {
            newArray[counter2++].push(array[i]);
            if (counter2 > parts - 1)
                counter2 = 0;
        }

        return newArray;
    } else 
        return array;
}

0
splitToChunks(arrayvar, parts) {
    let result = [];
    for (let i = parts; i > 0; i--) {
        result.push(arrayvar.splice(0, Math.ceil(arrayvar.length / i)));
    }
    return result;
}

0
有一个叫做PartitionJS的库可以完美地实现这个功能(全面披露,我是它的作者)。它可以将一个数组分割成你指定的任意数量的分区。
const data = [12, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1]
const [partitionTwo1, partitionTwo2] = partition().divide(data, 2)
const [partitionThree1, partitionThree2, partitionThree3] = partition().divide(data, 3);

将会产生这个结果
partitionTwo1 => [12, 2, 3, 4, 5, 6]
partitionTwo2 => [7, 8, 9, 10, 11, 1]

partitionThree1 => [12, 2, 3, 4]
partitionThree2 => [5, 6, 7, 8]
partitionThree3 => [9, 10, 11, 1]

如果分割方法不能按照您的要求完全划分数组,那么可以通过注册回调函数来完全控制每个分区中的内容。
const nums = [1, 2, 2, 4, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];

const splitSum = partition()
    .add(i => i < 6)
    .add(i => i > 5 && i < 11)
    .add(i => i > 10 && i < 14)
    .split(nums);

splitSum => [
    [1, 2, 2, 4, 1, 3, 4, 5],
    [6, 7, 8, 9, 10],
    [11, 12],
]

作为额外的好处,您还可以通过生成一个Web Worker(或在Node中生成一个Web线程)来异步地对数组进行分区,这将在单独的线程上对数组进行分区,以避免阻塞执行。
const reallyBigArray = [1, ... , 1000000]

console.log('--- start ---');

partition()
    .async()
    .add(i => i < 33)
    .add(i => i > 32 && i < 66)
    .add(i => i > 67)
    .split(reallyBigArray)
    .then(result => {
      console.log('Partitions done processing');
    });

console.log('--- UI element loaded ---');

'--- start ---'
'--- UI element loaded ---'
'Partitions done processing'

0

简单解决方案!!!

解决方案1:

var chunk = function(arr, size) {
   if(arr.length < size) return arr.length ? [arr]:[];
   return [arr.slice(0, size)].concat(chunk(arr.slice(size), size));
};

解决方案2:
var chunk = function(arr, size) {
   let out = [];
   for(let i = 0; i< arr.length; i = i+size) {
      out.push(arr.slice(i, i + size));
   }
   return out;
};

-3
如果您正在使用lodash,您可以很容易地像下面这样实现它:
import {chunk} from 'lodash';
// divides the array into 2 sections
chunk([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 2); // => [[1,2,3,4,5,6], [7,8,9,10,11]]

3
这是错误的。_.chunk 创建由 N 个元素组成的数组,而不是 N 个数组。 你的示例将生成6个数组,每个数组有2个元素,除了最后一个数组为[[1, 2],[3, 4],[5, 6],[7, 8],[9, 10],[11]] - Vassilis Barzokas
1
这就是原始问题。请阅读问题中的预期行为。 - abhisekpaul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接