将数组拆分为块

Ind*_*ial 442 javascript arrays split

假设我有一个Javascript数组,如下所示:

["Element 1","Element 2","Element 3",...]; // with close to a hundred elements.
Run Code Online (Sandbox Code Playgroud)

什么方法适合将数组块(拆分)到许多较小的数组中,比如最多10个元素?

Bla*_*ger 570

array.slice方法可以提取的开头,中间,或自己需要的任何目的数组的结束片,在不改变原来的数组.

var i,j,temparray,chunk = 10;
for (i=0,j=array.length; i<j; i+=chunk) {
    temparray = array.slice(i,i+chunk);
    // do whatever
}
Run Code Online (Sandbox Code Playgroud)

  • **对于单行(连锁爱好者)**:`const array_chunks =(array,chunk_size)=> Array(Math.ceil(array.length/chunk_size)).fill().map((_,index) => index*chunk_size).map(begin => array.slice(begin,begin + chunk_size));`. (42认同)
  • 不,最后一块应该比其他块小. (16认同)
  • 请记住,如果这是一个util函数来断言`chunk`为'0`.(无限循环) (11认同)
  • @Alex 这是一个微优化,缓存了 `j` 的值(如果 `j` 足够大,可以提高性能)。在你的代码中,`array.length` 在每次迭代时都被重新计算(或者至少是在我写这个答案的时候;我相信从那时起一些 JS 引擎已经改进了)。 (5认同)
  • 确实是@Blazemonger!下次我会在得出结论之前亲自尝试一下.我假设(错误地)将输入传递到超出数组边界的array.slice将是一个问题,但它工作得很完美! (4认同)
  • 你为什么需要j?首先,我认为这是一种优化,但实际上比for(i = 0; i &lt;array.length; i ++){}慢 (4认同)
  • 我找到另一行代码`const chunk = (arr, size) =&gt;Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =&gt;arr.slice(i * size) , i * 大小 + 大小)); console.log(chunk([1, 2, 3, 4, 5], 2));` 在 [链接](https://www.w3resource.com/javascript-exercises/fundamental/javascript-fundamental-exercise- 265.php) (3认同)
  • @gsalgadotoledo 为什么每次都重新创建新数组?您可以使用推送插入 (2认同)
  • @Blazemonger 这种微优化的问题是变量术语;)您可以在括号内使用“const length”而不是“j”,因为通常在计算机科学术语中“j”仅在有两个循环时使用,一个在另一个里面。`const` 不会污染其他作用域和外部作用域。 (2认同)

nin*_*cko 137

根据dbaseman的回答修改:https://stackoverflow.com/a/10456344/711085

Object.defineProperty(Array.prototype, 'chunk_inefficient', {
  value: function(chunkSize) {
    var array = this;
    return [].concat.apply([],
      array.map(function(elem, i) {
        return i % chunkSize ? [] : [array.slice(i, i + chunkSize)];
      })
    );
  }
});

console.log(
  [1, 2, 3, 4, 5, 6, 7].chunk_inefficient(3)
)
// [[1, 2, 3], [4, 5, 6], [7]]
Run Code Online (Sandbox Code Playgroud)

演示:

[[1,2,3]]~[]~[]~[] ~ [[4,5,6]]~[]~[]~[] ~ [[7]]
Run Code Online (Sandbox Code Playgroud)

次要补遗:

我应该指出,以上是一个不那么优雅(在我看来)使用的解决方法Array.map.它基本上做了以下,其中〜是连接:

// refresh page if experimenting and you already defined Array.prototype.chunk

Object.defineProperty(Array.prototype, 'chunk', {
  value: function(chunkSize) {
    var R = [];
    for (var i = 0; i < this.length; i += chunkSize)
      R.push(this.slice(i, i + chunkSize));
    return R;
  }
});

console.log(
  [1, 2, 3, 4, 5, 6, 7].chunk(3)
)
Run Code Online (Sandbox Code Playgroud)

它具有与下面方法相同的渐近运行时间,但由于构建空列表可能是一个更差的常数因子.有人可以按如下方式重写(大部分与Blazemonger的方法相同,这就是为什么我最初没有提交这个答案):

更有效的方法:

Array.range = function(n) {
  // Array.range(5) --> [0,1,2,3,4]
  return Array.apply(null,Array(n)).map((x,i) => i)
};

Object.defineProperty(Array.prototype, 'chunk', {
  value: function(n) {

    // ACTUAL CODE FOR CHUNKING ARRAY:
    return Array.range(Math.ceil(this.length/n)).map((x,i) => this.slice(i*n,i*n+n));

  }
});
Run Code Online (Sandbox Code Playgroud)

我现在的首选方式是上面的,或者下列之一:

> JSON.stringify( Array.range(10).chunk(3) );
[[1,2,3],[4,5,6],[7,8,9],[10]]
Run Code Online (Sandbox Code Playgroud)

演示:

var ceil = Math.ceil;

Object.defineProperty(Array.prototype, 'chunk', {value: function(n) {
    return Array(ceil(this.length/n)).fill().map((_,i) => this.slice(i*n,i*n+n));
}});
Run Code Online (Sandbox Code Playgroud)

或者如果你不想要一个Array.range函数,它实际上只是一个单行(不包括绒毛):

Object.defineProperty(Array.prototype, 'chunk', {value: function(n) {
    return Array.from(Array(ceil(this.length/n)), (_,i)=>this.slice(i*n,i*n+n));
}});
Run Code Online (Sandbox Code Playgroud)

要么

Object.defineProperty(Array.prototype, 'chunk_inefficient', {
  value: function(chunkSize) {
    var array = this;
    return [].concat.apply([],
      array.map(function(elem, i) {
        return i % chunkSize ? [] : [array.slice(i, i + chunkSize)];
      })
    );
  }
});

console.log(
  [1, 2, 3, 4, 5, 6, 7].chunk_inefficient(3)
)
// [[1, 2, 3], [4, 5, 6], [7]]
Run Code Online (Sandbox Code Playgroud)

  • 呃,我会避免弄乱原型,因为你在调用阵列上的`chunk`函数时得到的酷感并没有真正超过你添加的额外复杂性以及弄乱内置原型的微妙错误可以引起. (31认同)
  • 他没有弄乱他们,他正在为阵列扩展它们.我理解从不接触Object.prototype,因为它会冒泡到所有对象(一切),但对于这个特定于Array的函数,我没有看到任何问题. (10认同)
  • @rlemon 给你,这是导致的问题。请永远不要修改原生原型,特别是没有供应商前缀:https://developers.google.com/web/updates/2018/03/smooshgate 如果添加 `array.myCompanyFlatten` 就可以了,但请不要添加 `array.myCompanyFlatten`。压平`并祈祷它永远不会引起问题。正如您所看到的,mootools 几年前的决定现在影响着 TC39 标准。 (7认同)
  • 基于mozilla开发站点上的兼容性图表,针对IE9 +的Array.map.小心. (3认同)
  • @rlemon它仍然很危险,因为它可能与其他人所做的或与未来的方法发生冲突。为了安全起见,只需创建一个接受数组的方法即可完全避免出现问题。https:// humanwhocodes.com/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/ (2认同)

小智 91

如果您不知道谁将消耗您的代码(第三方,同事,您自己以后等),请尽量避免使用本机原型(包括Array.prototype).

有一些方法可以安全地扩展原型(但不是在所有浏览器中),并且有方法可以安全地使用从扩展原型创建的对象,但更好的经验法则是遵循最小惊喜原则并完全避免这些做法.

如果您有时间,请观看Andrew Dupont的JSConf 2011演讲,"Everything is Permitted:Extending Built-ins",以便对此主题进行讨论.

但回到这个问题,虽然上述解决方案可行,但它们过于复杂,需要不必要的计算开销.这是我的解决方案:

function chunk (arr, len) {

  var chunks = [],
      i = 0,
      n = arr.length;

  while (i < n) {
    chunks.push(arr.slice(i, i += len));
  }

  return chunks;
}

// Optionally, you can do the following to avoid cluttering the global namespace:
Array.chunk = chunk;
Run Code Online (Sandbox Code Playgroud)

  • "避免与原生原型混淆"新js开发人员应该获得这个短语的临时(如果不是永久性的)纹身. (17认同)
  • 我已经使用 javascript 多年,几乎没有时间花在原型上,最多调用函数,从不像你看到的某些人那样修改。 (2认同)
  • 我眼中最好的建议,最容易理解和执行,非常感谢! (2认同)
  • @JacobDalton 我认为这都是大学的错。人们认为 OOP 必须无处不在。所以他们害怕“只是创建一个功能”。他们希望确保将其放入某物中。即使它根本不合适。如果没有点符号,就没有“架构”。 (2认同)

And*_*i R 80

这是使用reduce的ES6版本

var perChunk = 2 // items per chunk    

var inputArray = ['a','b','c','d','e']

var result = inputArray.reduce((resultArray, item, index) => { 
  const chunkIndex = Math.floor(index/perChunk)

  if(!resultArray[chunkIndex]) {
    resultArray[chunkIndex] = [] // start a new chunk
  }

  resultArray[chunkIndex].push(item)

  return resultArray
}, [])

console.log(result); // result: [['a','b'], ['c','d'], ['e']]
Run Code Online (Sandbox Code Playgroud)

而且您已准备好进一步链接地图/减少转换.您的输入数组保持不变


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

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

  • 阅读这样的解决方案,我真的想知道人们是否再考虑过他们算法的空间/时间复杂性。concat() 克隆数组,这意味着该算法不仅会像 @JPdelaTorre 注意到的那样迭代每个元素,而且还会对每个其他元素进行迭代。对于 100 万个项目(这对于任何实际用例来说实际上并不奇怪),该算法在我的 PC 上运行需要近 22 秒,而接受的答案需要 8 毫秒。FP队加油! (8认同)
  • 我喜欢你在这里使用“all”和“one”——与我见过和使用的其他示例相比,reduce 更容易被我的大脑阅读。 (5认同)
  • 来自热爱函数式编程的人的热门观点,for 循环比简化为新数组更具可读性 (3认同)

Aym*_*Kdn 40

我在jsperf.com上测试了不同的答案.结果可以在那里找到:http://jsperf.com/chunk-mtds

最快的功能(和IE8一样)是这样的:

function chunk(arr, chunkSize) {
  var R = [];
  for (var i=0,len=arr.length; i<len; i+=chunkSize)
    R.push(arr.slice(i,i+chunkSize));
  return R;
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一个打字稿版本: `function chunk&lt;T&gt;(array: T[], chunkSize: number): T[][] { const R = []; for (let i = 0, len = array.length; i &lt; len; i += chunkSize) R.push(array.slice(i, i + chunkSize)); 返回R;}` (2认同)

小智 30

我更喜欢使用拼接方法:

var chunks = function(array, size) {
  var results = [];
  while (array.length) {
    results.push(array.splice(0, size));
  }
  return results;
};
Run Code Online (Sandbox Code Playgroud)

  • 必须小心这个拼接解决方案,因为它修改了原始数组,所以一定要清楚地记录副作用. (14认同)
  • 然后使用切片代替 (3认同)
  • 或者,如果您无法使用 ES6 功能,您可以简单地使用“array = array.slice()”,它也会创建一个浅拷贝。 (2认同)

rle*_*mon 28

老问题:新答案!我实际上正在处理这个问题的答案并让朋友改进了!所以这里是:

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]]
Run Code Online (Sandbox Code Playgroud)

  • fyi,这个方法的性能是O(N ^ 2),所以它不应该用在代码的性能关键部分,或者用于长数组(特别是当数组的`.length`远大于块时 - 尺寸`n`).如果这是一种懒惰的语言(与javascript不同),该算法不会受到O(N ^ 2)时间的影响.也就是说,递归实现很优雅.您可以通过首先定义一个辅助函数来修改它以提高性能,该函数在`array,position`上进行递归,然后调度:`Array.prototype.chunk`返回[你的帮助函数](...) (14认同)

Sha*_*edo 28

ECMA 6中的单线程

const [list,chuckSize] = [[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], 6]

new Array(Math.ceil(list.length / chuckSize)).fill().map(_ => list.splice(0,chuckSize))
Run Code Online (Sandbox Code Playgroud)

  • 它修改了原始的`list`数组 (7认同)
  • 使用.slice()轻松修复.` .map((_,i)=> list.slice(i*chuckSize,i*chuckSize + chuckSize)) (6认同)
  • 在JSPerf上,这比许多其他答案的性能要高得多. (2认同)

小智 25

现在你可以使用lodash'chunk函数将数组拆分成更小的数组https://lodash.com/docs#chunk不再需要摆弄循环了!

  • 我觉得应该对SO javascript问题有免责声明:你试过lodash吗?几乎是我在节点或浏览器中包含的第一件事. (3认同)

mar*_*ias 19

另一种解决方案使用Array.prototype.reduce()

const chunk = (array, size) =>
  array.reduce((acc, _, i) => {
    if (i % size === 0) acc.push(array.slice(i, i + size))
    return acc
  }, [])

// Usage:
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const chunked = chunk(numbers, 3)
console.log(chunked)
Run Code Online (Sandbox Code Playgroud)

此解决方案与Steve Holgado解决方案非常相似。但是,由于此解决方案不利用数组扩展并且不在 reducer 函数中创建新数组,因此它比其他解决方案更快(请参阅jsPerf 测试)并且主观上更具可读性(更简单的语法)。

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

如果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
}
Run Code Online (Sandbox Code Playgroud)


nki*_*tku 14

单线

const chunk = (a,n)=>[...Array(Math.ceil(a.length/n))].map((_,i)=>a.slice(n*i,n+n*i));
Run Code Online (Sandbox Code Playgroud)

对于打字稿

const chunk = <T>(arr: T[], size: number): T[][] =>
  [...Array(Math.ceil(arr.length / size))].map((_, i) =>
    arr.slice(size * i, size + size * i)
  );
Run Code Online (Sandbox Code Playgroud)

演示

const chunk = <T>(arr: T[], size: number): T[][] =>
  [...Array(Math.ceil(arr.length / size))].map((_, i) =>
    arr.slice(size * i, size + size * i)
  );
Run Code Online (Sandbox Code Playgroud)

按组数分组

const chunk = (a,n)=>[...Array(Math.ceil(a.length/n))].map((_,i)=>a.slice(n*i,n+n*i));
document.write(JSON.stringify(chunk([1, 2, 3, 4], 2)));
Run Code Online (Sandbox Code Playgroud)

对于打字稿

const part = <T>(a: T[], n: number): T[][] => {
  const b = Math.ceil(a.length / n);
  return [...Array(n)].map((_, i) => a.slice(i * b, (i + 1) * b));
};
Run Code Online (Sandbox Code Playgroud)

演示

const part=(a,n)=>[...Array(n)].map((_,i)=>a.slice(i*Math.ceil(a.length/n),(i+1)*Math.ceil(a.length/n)));
Run Code Online (Sandbox Code Playgroud)


use*_*558 13

好吧,让我们从一个相当紧张的开始:

function chunk(arr, n) {
    return arr.slice(0,(arr.length+n-1)/n|0).
           map(function(c,i) { return arr.slice(n*i,n*i+n); });
}
Run Code Online (Sandbox Code Playgroud)

使用方式如下:

chunk([1,2,3,4,5,6,7], 2);
Run Code Online (Sandbox Code Playgroud)

然后我们有这个紧缩的减速器功能:

function chunker(p, c, i) {
    (p[i/this|0] = p[i/this|0] || []).push(c);
    return p;
}
Run Code Online (Sandbox Code Playgroud)

使用方式如下:

[1,2,3,4,5,6,7].reduce(chunker.bind(3),[]);
Run Code Online (Sandbox Code Playgroud)

因为当我们绑定this一个数字时小猫死了,我们可以这样做手动currying:

// Fluent alternative API without prototype hacks.
function chunker(n) {
   return function(p, c, i) {
       (p[i/n|0] = p[i/n|0] || []).push(c);
       return p;
   };
}
Run Code Online (Sandbox Code Playgroud)

使用方式如下:

[1,2,3,4,5,6,7].reduce(chunker(3),[]);
Run Code Online (Sandbox Code Playgroud)

然后仍然非常紧凑的功能,一气呵成:

function chunk(arr, n) {
    return arr.reduce(function(p, cur, i) {
        (p[i/n|0] = p[i/n|0] || []).push(cur);
        return p;
    },[]);
}

chunk([1,2,3,4,5,6,7], 3);
Run Code Online (Sandbox Code Playgroud)

  • 哈!我爱小猫评论.对不起,没有额外的建设性意见:) (2认同)

Ger*_*ári 11

我认为这是一个很好的递归解决方案与ES6语法:

const chunk = function(array, size) {
  if (!array.length) {
    return [];
  }
  const head = array.slice(0, size);
  const tail = array.slice(size);

  return [head, ...chunk(tail, size)];
};

console.log(chunk([1,2,3], 2));
Run Code Online (Sandbox Code Playgroud)


tho*_*dge 10

我的目标是在纯ES6中创建一个简单的非变异解决方案.javascript中的特性使得必须在映射之前填充空数组:-(

function chunk(a, l) { 
    return new Array(Math.ceil(a.length / l)).fill(0)
        .map((_, n) => a.slice(n*l, n*l + l)); 
}
Run Code Online (Sandbox Code Playgroud)

这个带递归的版本看起来更简单,更引人注目:

function chunk(a, l) { 
    if (a.length == 0) return []; 
    else return [a.slice(0, l)].concat(chunk(a.slice(l), l)); 
}
Run Code Online (Sandbox Code Playgroud)

ES6奇怪的弱阵列功能带来了很好的难题:-)


小智 10

我建议使用 lodash。分块是其中许多有用的功能之一。指示:

npm i --save lodash
Run Code Online (Sandbox Code Playgroud)

包含在您的项目中:

import * as _ from 'lodash';
Run Code Online (Sandbox Code Playgroud)

用法:

const arrayOfElements = ["Element 1","Element 2","Element 3", "Element 4", "Element 5","Element 6","Element 7","Element 8","Element 9","Element 10","Element 11","Element 12"]
const chunkedElements = _.chunk(arrayOfElements, 10)
Run Code Online (Sandbox Code Playgroud)

您可以在这里找到我的示例: https: //playcode.io/659171/


use*_*043 9

以下 ES2015 方法无需定义函数并直接在匿名数组上工作(块大小为 2 的示例):

[11,22,33,44,55].map((_, i, all) => all.slice(2*i, 2*i+2)).filter(x=>x.length)
Run Code Online (Sandbox Code Playgroud)

如果您想为此定义一个函数,您可以按如下方式进行(改进K._Blazemonger 的回答的评论):

const array_chunks = (array, chunk_size) => array
    .map((_, i, all) => all.slice(i*chunk_size, (i+1)*chunk_size))
    .filter(x => x.length)
Run Code Online (Sandbox Code Playgroud)


小智 9

const array = ['a', 'b', 'c', 'd', 'e'];
const size = 2;
const chunks = [];
while (array.length) {
    chunks.push(array.splice(0, size));
}
console.log(chunks);
Run Code Online (Sandbox Code Playgroud)


Bar*_*uri 9

js

function splitToBulks(arr, bulkSize = 20) {
    const bulks = [];
    for (let i = 0; i < Math.ceil(arr.length / bulkSize); i++) {
        bulks.push(arr.slice(i * bulkSize, (i + 1) * bulkSize));
    }
    return bulks;
}

console.log(splitToBulks([1, 2, 3, 4, 5, 6, 7], 3));
Run Code Online (Sandbox Code Playgroud)

打字稿

function splitToBulks<T>(arr: T[], bulkSize: number = 20): T[][] {
    const bulks: T[][] = [];
    for (let i = 0; i < Math.ceil(arr.length / bulkSize); i++) {
        bulks.push(arr.slice(i * bulkSize, (i + 1) * bulkSize));
    }
    return bulks;
}
Run Code Online (Sandbox Code Playgroud)


mat*_*sev 8

如果使用EcmaScript版本> = 5.1,则可以实现chunk()使用具有O(N)复杂度的array.reduce()的功能版本:

function chunk(chunkSize, array) {
    return array.reduce(function(previous, current) {
        var chunk;
        if (previous.length === 0 || 
                previous[previous.length -1].length === chunkSize) {
            chunk = [];   // 1
            previous.push(chunk);   // 2
        }
        else {
            chunk = previous[previous.length -1];   // 3
        }
        chunk.push(current);   // 4
        return previous;   // 5
    }, []);   // 6
}

console.log(chunk(2, ['a', 'b', 'c', 'd', 'e']));
// prints [ [ 'a', 'b' ], [ 'c', 'd' ], [ 'e' ] ]
Run Code Online (Sandbox Code Playgroud)

// nbr上述各项说明:

  1. 如果先前的值(即先前返回的块数组)为空或者上一个上一个块具有chunkSize项目,则创建一个新块
  2. 将新块添加到现有块的数组中
  3. 否则,当前块是块数组中的最后一个块
  4. 将当前值添加到块中
  5. 返回修改后的块数组
  6. 通过传递一个空数组来初始化减少

Currying基于chunkSize:

var chunk3 = function(array) {
    return chunk(3, array);
};

console.log(chunk3(['a', 'b', 'c', 'd', 'e']));
// prints [ [ 'a', 'b', 'c' ], [ 'd', 'e' ] ]
Run Code Online (Sandbox Code Playgroud)

您可以将该chunk()函数添加到全局Array对象:

Object.defineProperty(Array.prototype, 'chunk', {
    value: function(chunkSize) {
        return this.reduce(function(previous, current) {
            var chunk;
            if (previous.length === 0 || 
                    previous[previous.length -1].length === chunkSize) {
                chunk = [];
                previous.push(chunk);
            }
            else {
                chunk = previous[previous.length -1];
            }
            chunk.push(current);
            return previous;
        }, []);
    }
});

console.log(['a', 'b', 'c', 'd', 'e'].chunk(4));
// prints [ [ 'a', 'b', 'c' 'd' ], [ 'e' ] ]
Run Code Online (Sandbox Code Playgroud)


Ike*_*Eze 8

使用发电机

function* chunks(arr, n) {
 for(let i = 0; i < arr.length; i += n) {
     yield(arr.slice(i, i+n));
     }
}
let someArray = [0,1,2,3,4,5,6,7,8,9]
console.log([...chunks(someArray, 2)]) // [[0,1],[2,3],[4,5],[6,7],[8,9]]
Run Code Online (Sandbox Code Playgroud)

  • 我对这个问题的所有答案感到惊讶,这些答案几乎都在使用生成器或以更复杂的方式使用它们。此解决方案的简洁性和性能非常好。 (5认同)
  • `function* chunks&lt;T&gt;(arr: T[], n: number): Generator&lt;T[], void&gt; {` 然后使用 `const foo = [ ...chunks( bar, 4 ) ];` - @雷福斯 (2认同)

Saj*_*med 8

使用Array.prototype.splice()和拼接直到数组有元素。

Array.prototype.chunk = function(size) {
    let result = [];
    
    while(this.length) {
        result.push(this.splice(0, size));
    }
        
    return result;
}

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(arr.chunk(2));
Run Code Online (Sandbox Code Playgroud)

更新

Array.prototype.splice()填充原始数组并在执行chunk()原始数组 ( arr) 后变为[].

因此,如果您想保持原始数组不变,则将arr数据复制并保留到另一个数组中并执行相同的操作。

Array.prototype.chunk = function(size) {
  let data = [...this];  
  let result = [];
    
    while(data.length) {
        result.push(data.splice(0, size));
    }

    return result;
}

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log('chunked:', arr.chunk(2));
console.log('original', arr);
Run Code Online (Sandbox Code Playgroud)

PS:感谢@mts-knn 提及此事。


小智 8

您可以使用 Array.prototype.reduce 函数在一行中完成此操作。

let arr = [1,2,3,4];
function chunk(arr, size)
{
    let result = arr.reduce((rows, key, index) => (index % size == 0 ? rows.push([key]) : rows[rows.length-1].push(key)) && rows, []);
    return result;
}
        
console.log(chunk(arr,2));
Run Code Online (Sandbox Code Playgroud)


小智 7

in coffeescript:

b = (a.splice(0, len) while a.length)

demo 
a = [1, 2, 3, 4, 5, 6, 7]

b = (a.splice(0, 2) while a.length)
[ [ 1, 2 ],
  [ 3, 4 ],
  [ 5, 6 ],
  [ 7 ] ]
Run Code Online (Sandbox Code Playgroud)

  • 我建议使用非破坏性slice()方法而不是splice() (2认同)

Jon*_*Jon 7

results = []
chunk_size = 10
while(array.length > 0){
   results.push(array.splice(0, chunk_size))
}
Run Code Online (Sandbox Code Playgroud)

  • 因为拼接会破坏原始数组。 (2认同)

Ste*_*ado 7

有很多答案,但这是我使用的:

const chunk = (arr, size) =>
  arr
    .reduce((acc, _, i) =>
      (i % size)
        ? acc
        : [...acc, arr.slice(i, i + size)]
    , [])

// USAGE
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
chunk(numbers, 3)

// [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
Run Code Online (Sandbox Code Playgroud)

首先,在将索引除以块大小时检查余数.

如果有余数,则返回累加器数组.

如果没有余数,那么索引可以被块大小整除,所以从原始数组中取一个切片(从当前索引开始)并将其添加到累加器数组.

因此,reduce的每次迭代返回的累加器数组看起来像这样:

// 0: [[1, 2, 3]]
// 1: [[1, 2, 3]]
// 2: [[1, 2, 3]]
// 3: [[1, 2, 3], [4, 5, 6]]
// 4: [[1, 2, 3], [4, 5, 6]]
// 5: [[1, 2, 3], [4, 5, 6]]
// 6: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
// 7: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
// 8: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
// 9: [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
Run Code Online (Sandbox Code Playgroud)


Mil*_*ary 7

使用来自 lodash 的块

lodash.chunk(arr,<size>).forEach(chunk=>{
  console.log(chunk);
})
Run Code Online (Sandbox Code Playgroud)


Rei*_*n F 7

这是一个示例,我将数组拆分为 2 个元素的块,只需将块从数组中拼接出来,直到原始数组为空。

    const array = [86,133,87,133,88,133,89,133,90,133];
    const new_array = [];

    const chunksize = 2;
    while (array.length) {
        const chunk = array.splice(0,chunksize);
        new_array.push(chunk);
    }

    console.log(new_array)
Run Code Online (Sandbox Code Playgroud)


met*_*gfu 7

纯 javascript 中的一行:

function chunks(array, size) {
  return Array.apply(0,{length: Math.ceil(array.length / size)}).map((_, index) => array.slice(index*size, (index+1)*size))
}

// The following will group letters of the alphabet by 4
console.log(chunks([...Array(26)].map((x,i)=>String.fromCharCode(i + 97)), 4))
Run Code Online (Sandbox Code Playgroud)


zhi*_*lee 6

为此https://www.npmjs.com/package/array.chunk创建了一个npm包

  var result = [];
  for (var i = 0; i < arr.length; i += size) {
    result.push(arr.slice(i, size + i));
  }

  return result;
Run Code Online (Sandbox Code Playgroud)


goo*_*gic 6

ES6 传播功能性#ohmy #ftw

const chunk =
  (size, xs) => 
    xs.reduce(
      (segments, _, index) =>
        index % size === 0 
          ? [...segments, xs.slice(index, index + size)] 
          : segments, 
      []
    );

console.log( chunk(3, [1, 2, 3, 4, 5, 6, 7, 8]) );
Run Code Online (Sandbox Code Playgroud)


Ben*_*uer 6

可以拿这个ES6chunk函数,好用:

const chunk = (array, size) =>
  Array.from({length: Math.ceil(array.length / size)}, (value, index) => array.slice(index * size, index * size + size));

const itemsPerChunk = 3;
const inputArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];

const newArray = chunk(inputArray, itemsPerChunk);
console.log(newArray.length); // 3,

document.write(JSON.stringify(newArray)); //  [ [ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ], [ 'g' ] ]
Run Code Online (Sandbox Code Playgroud)


you*_*ayy 6

随着源数组的变化:

let a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ], aa = [], x
while((x = a.splice(0, 2)).length) aa.push(x)

// aa == [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ], [ 9 ] ]
// a == []
Run Code Online (Sandbox Code Playgroud)

不改变源数组:

let a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ], aa = []
for(let i = 0; i < a.length; i += 2) aa.push(a.slice(i, i + 2))

// aa == [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ], [ 9 ] ]
// a == [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
Run Code Online (Sandbox Code Playgroud)


Rm5*_*558 5

ES6生成器版本

function* chunkArray(array,size=1){
    var clone = array.slice(0);
    while (clone.length>0) 
      yield clone.splice(0,size); 
};
var a = new Array(100).fill().map((x,index)=>index);
for(const c of chunkArray(a,10)) 
    console.log(c);
Run Code Online (Sandbox Code Playgroud)


Red*_*edu 5

这将是我对这个主题的贡献.我猜.reduce()是最好的方法.

var segment = (arr, n) => arr.reduce((r,e,i) => i%n ? (r[r.length-1].push(e), r)
                                                    : (r.push([e]), r), []),
        arr = Array.from({length: 31}).map((_,i) => i+1);
        res = segment(arr,7);
console.log(JSON.stringify(res));
Run Code Online (Sandbox Code Playgroud)

但是,由于.reduce()贯穿所有arr功能,上述实现效率不高.一种更有效的方法(非常接近最快的命令式解决方案)将迭代在减少的(待分块的)阵列上,因为我们可以提前计算它的大小Math.ceil(arr/n);.一旦我们得到空结果数组,就像Array(Math.ceil(arr.length/n)).fill();其余数据一样,将arr数组的切片映射到其中.

function chunk(arr,n){
  var r = Array(Math.ceil(arr.length/n)).fill();
  return r.map((e,i) => arr.slice(i*n, i*n+n));
}

arr = Array.from({length: 31},(_,i) => i+1);
res = chunk(arr,7);
console.log(JSON.stringify(res));
Run Code Online (Sandbox Code Playgroud)


Dam*_*een 5

对于功能解决方案,使用Ramda

popularProducts你的输入数组在哪里,5是块大小

import splitEvery from 'ramda/src/splitEvery'

splitEvery(5, popularProducts).map((chunk, i) => {
// do something with chunk

})
Run Code Online (Sandbox Code Playgroud)


小智 5

这是尾调用优化的递归解决方案。

const splitEvery = (n, xs, y=[]) =>
  xs.length===0 ? y : splitEvery(n, xs.slice(n), y.concat([xs.slice(0, n)])) 

console.log(splitEvery(2, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
Run Code Online (Sandbox Code Playgroud)


use*_*066 5

如果您使用的是 Underscore JS,只需使用:

var result = _.chunk(arr,elements_per_chunk)
Run Code Online (Sandbox Code Playgroud)

无论如何,大多数项目已经使用下划线作为依赖项。