将一个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个回答

2

递归方法,未经测试。

function splitArray(array, parts, out) {
    var
        len = array.length
        , partLen

    if (parts < len) {
        partLen = Math.ceil(len / parts);
        out.push(array.slice(0, partLen));
        if (parts > 1) {
            splitArray(array.slice(partLen), parts - 1, out);
        }
    } else {
        out.push(array);
    }
}

2

Partition

const partition = (x,n) => {
  const p=x.length%n, q=Math.ceil(x.length/n), r=Math.floor(x.length/n);
  return [...Array(n)].reduce((a,_,i)=>(a[0].push(x.slice(a[1],(a[1]+=i<p?q:r))),a),[[],0])[0];
};

演示

// to make it consistent to filter pass index and array as arguments
const partition = (x,n) => {
    const p = x.length % n,q = Math.ceil(x.length / n),r = Math.floor(x.length / n);
    return [...Array(n)].reduce((a,_,i)=>(a[0].push(x.slice(a[1],(a[1]+=i<p?q:r))),a),[[],0])[0];
};

console.log(partition([], 3))
console.log(partition([1, 2], 3))
console.log(partition([1, 2, 3, 4, 5, 6, 7, 8, 9], 3))
console.log(partition([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3))

针对 TypeScript

const partition = <T>(x: T[], n: number) => {
    const p = x.length % n, q = Math.ceil(x.length / n), r = Math.floor(x.length / n);
    return [...Array(n) as never[]].reduce((a, _, i) =>
        (a[0].push(x.slice(a[1], a[1] += i < p ? q : r)), a)
        , [[], 0] as [T[][], number])[0]
}

一行命令分区(但顺序不同)

const part=(x,n)=>x.reduce((a,v,i)=>(a[i%n].push(v),a),[...Array(n)].map(()=>[]));

演示

// to make it consistent to filter pass index and array as arguments
const part=(x,n)=>x.reduce((a,v,i)=>(a[i%n].push(v),a),[...Array(n)].map(()=>[]));

console.log(part([1, 2, 3, 4, 5], 3));
console.log(part([1, 2, 3, 4, 5, 6], 3));
console.log(part([1, 2], 3));

对于Typescript


const part = <T>(array: T[], parts: number) =>
  array.reduce(
    (acc, value, i) => (acc[i % parts].push(value), acc),
    [...Array(parts)].map(() => []) as T[][]
  );

小修正ts的const partition = <T,>(x: T[], n: number) => { - victor zadorozhnyy

1

1
问题要求使用原生JS解决,而不是使用JS库。 - T J
4
谢谢你提出这个问题。我不知道lodash有这个功能。 - Tiago
9
这也没有回答问题。他想要N个数组,而不是由N个元素构成的数组。 - mAAdhaTTah

1
也许更加清晰的方法是以下方式(不使用任何其他库):
var myArray = [];
for(var i=0; i<100; i++){
  myArray.push(i+1);
}
console.log(myArray);

function chunk(arr, size){
  var chunkedArr = [];
  var noOfChunks = Math.ceil(arr.length/size);
  console.log(noOfChunks);
  for(var i=0; i<noOfChunks; i++){
    chunkedArr.push(arr.slice(i*size, (i+1)*size));
  }
   return chunkedArr;
}

var chunkedArr = chunk(myArray, 3);
console.log(chunkedArr);

我已经创建了自己的数组,需要分块。您可以在这里找到代码here 此外,我们在Lodash库中有一个名为“chunk”的方法,非常有用。希望这有所帮助。

0

我有一个不改变原始数组的

function splitArray(array = [], nPieces = 1){
    const splitArray = [];
    let atArrPos = 0;
    for(let i = 0; i < nPieces; i++){
        const splitArrayLength  = Math.ceil((array.length - atArrPos)/ (nPieces - i));
        splitArray.push([]);
        splitArray[i] = array.slice(atArrPos, splitArrayLength + atArrPos);
        atArrPos += splitArrayLength;
    }
    return  splitArray
}


0

你可以使用一个简单的递归函数

const chunkify = (limit, completeArray, finalArray = [])=>{
    if(!completeArray.length) return finalArray
    const a = completeArray.splice(0,limit);
    return chunkify(limit, completeArray, [...finalArray,a])
}


0

如果您可以使用lodash并且希望采用函数式编程方法,这是我想到的:

const _ = require('lodash')

function splitArray(array, numChunks) {
  return _.reduce(_.range(numChunks), ({array, result, numChunks}, chunkIndex) => {
    const numItems = Math.ceil(array.length / numChunks)
    const items = _.take(array, numItems)
    result.push(items)
    return {
      array: _.drop(array, numItems),
      result,
      numChunks: numChunks - 1
    }
  }, {
    array,
    result: [],
    numChunks
  }).result
} 

0

检查一下我对这个数组分割的版本

// divide array
Array.prototype.divideIt = function(d){
    if(this.length <= d) return this;
    var arr = this,
        hold = [],
        ref = -1;
    for(var i = 0; i < arr.length; i++){
        if(i % d === 0){
            ref++;
        }
        if(typeof hold[ref] === 'undefined'){
            hold[ref] = [];
        }
        hold[ref].push(arr[i]);
    }

    return hold;
};

0

以上的方法可能都能正常工作,但如果你有一个以字符串为键的关联数组呢?

objectKeys = Object.keys;

arraySplit(arr, n) {
    let counter = 0;
    for (const a of this.objectKeys(arr)) {
        this.arr[(counter%n)][a] = arr[a];
        counter++;
    }
}

0
如果你不想设置child_arrays.length,那么我认为这个解决方案是最好的:
function sp(size, arr){ //size - child_array.length
    var out = [],i = 0, n= Math.ceil((arr.length)/size); 
    while(i < n) { out.push(arr.splice(0, (i==n-1) && size < arr.length ? arr.length: size));  i++;} 
    return out;
}

调用函数: sp(2, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) // 2 - 子数组长度

答案: [1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11]


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