让我们说我有一个Javascript数组看起来如下:

["Element 1","Element 2","Element 3",...]; // with close to a hundred elements.

什么样的方法适合将数组分成许多更小的数组,假设最多有10个元素?


当前回答

老问题:新答案!事实上,我一直在想这个问题的答案,并让一个朋友改进了它!就是这样:

Array.prototype.chunk = function ( n ) {
    if ( !this.length ) {
        return [];
    }
    return [ this.slice( 0, n ) ].concat( this.slice(n).chunk(n) );
};

[1,2,3,4,5,6,7,8,9,0].chunk(3);
> [[1,2,3],[4,5,6],[7,8,9],[0]]

其他回答

使用Array.prototype.reduce()的另一个解决方案:

Const chunk = (array, size) => 数组中。Reduce ((acc, _, i) => { If (i % size === 0) ac .push(数组。切片(i, i + size)) 返回acc }, []) / /使用方法: Const数= [1,2,3,4,5,6,7,8,9,10] Const chunked = chunk(number, 3) console.log(分块)

这个解决方案与Steve Holgado的解决方案非常相似。但是,因为这个解决方案没有利用数组扩展,也没有在reducer函数中创建新数组,所以它比其他解决方案更快(参见jsPerf test),而且主观上更可读(语法更简单)。

在每n次迭代(其中n = size;从第一次迭代开始),累加器数组(acc)附加了数组的一个块(array。Slice (i, i + size)),然后返回。在其他迭代中,累加器数组按原样返回。

如果size为零,该方法返回一个空数组。如果size为负,则该方法返回破碎的结果。因此,如果在您的情况下需要,您可能需要对负的或非正的大小值进行处理。


如果在你的情况下速度很重要,一个简单的for循环将比使用reduce()更快(参见jsPerf测试),一些人可能会发现这种风格更易于阅读:

function chunk(array, size) {
  // This prevents infinite loops
  if (size < 1) throw new Error('Size must be positive')

  const result = []
  for (let i = 0; i < array.length; i += size) {
    result.push(array.slice(i, i + size))
  }
  return result
}

下面是使用reduce()方法的另一个解决方案,尽管与其他示例略有不同。希望我的解释也能更清楚一点。

Var arr = [0,1,2,3,4,5,6,7]; var chunkSize = 3; Arr = Arr。Reduce ((acc, item, idx) => { Let group = acc.pop(); 如果(集团。长度== chunkSize) { acc.push(集团); Group = []; } group.push(项); acc.push(集团); 返回acc; }, [[]]); console.log (arr);//打印[[0,1,2],[3,4,5],[6,7]]


解释

我们称之为reducer,它对数组中的每一项都使用pop()获取累加器的最后一项。记住,这个项是一个数组,它将最多为chunkSize数量的项进行分组(在本例中为3)。

当且仅当该组的数组长度等于chunksize时,我们需要将该组重新插入到累加器中并创建一个新组。

然后将当前项推入我们的组数组(它可能已经包含前面步骤中的0、1或2个项)。将当前项插入组后,我们需要将组重新插入到更大的集合中。

该过程将重复进行,直到遍历arr中的所有项。

注意,我们还使用[[]]为减速器提供了数组中空数组的起始值。

# in coffeescript
# assume "ar" is the original array
# newAr is the new array of arrays

newAr = []
chunk = 10
for i in [0... ar.length] by chunk
   newAr.push ar[i... i+chunk]

# or, print out the elements one line per chunk
for i in [0... ar.length] by chunk
   console.log ar[i... i+chunk].join ' '

这里是一个仅使用递归和slice()的非突变解决方案。

const splitToChunks = (arr, chunkSize, acc = []) => (
    arr.length > chunkSize ?
        splitToChunks(
            arr.slice(chunkSize),
            chunkSize,
            [...acc, arr.slice(0, chunkSize)]
        ) :
        [...acc, arr]
);

然后简单地像splitToChunks([1,2,3,4,5], 3)一样使用它来获得[[1,2,3],[4,5]]。

这里有一个小提琴供你尝试:https://jsfiddle.net/6wtrbx6k/2/

下面是一个使用reduce的ES6版本

const perChunk = 2 //每个chunk有2个项目 const inputArray = ['a','b','c','d','e'] const result = inputArray。reduce((resultArray, item, index) => { const chunkIndex = Math.floor(index/perChunk) 如果(! resultArray [chunkIndex]) { resultArray[chunkIndex] =[] //启动一个新的chunk } resultArray [chunkIndex] .push(项) 返回resultArray }, []) console.log(结果);// result: [['a','b'], ['c','d'], ['e']]]

并且您已经准备好连接进一步的映射/缩减转换。 输入数组保持不变


如果你喜欢更短但可读性较差的版本,你可以在混合中添加一些concat,以获得相同的最终结果:

inputArray.reduce((all,one,i) => {
   const ch = Math.floor(i/perChunk); 
   all[ch] = [].concat((all[ch]||[]),one); 
   return all
}, [])

你可以使用余数运算符将连续的项放入不同的块中:

const ch = (i % perChunk);