将数组拆分为块

IT技术 javascript arrays split
2020-12-12 01:11:45

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

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

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

6个回答

array.slice方法可以根据需要从数组的开头、中间或结尾提取切片,而无需更改原始数组。

var i,j, temporary, chunk = 10;
for (i = 0,j = array.length; i < j; i += chunk) {
    temporary = array.slice(i, i + chunk);
    // do whatever
}
不,最后一块应该比其他块小。
2021-02-08 01:11:45
请记住,如果这是一个实用程序功能的断言对chunk0(无限循环)
2021-02-13 01:11:45
为什么需要j?一开始我还以为是优化,其实比 for(i=0;i<array.length;i++){}
2021-02-13 01:11:45
@Blazemonger,确实!下次我会亲自尝试一下,然后再下结论。我假设(错误地)将超出数组边界的输入传递给 array.slice 会是一个问题,但它工作得非常完美!
2021-02-17 01:11:45
对于单行(链爱好者)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));
2021-02-27 01:11:45

这是使用 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']]

并且您已准备好链接进一步的 map/reduce 转换。您的输入数组保持不变


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

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

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

const ch = (i % perChunk); 
我喜欢你在这里使用allone- 比我见过和使用的其他例子更容易阅读我的大脑。
2021-02-07 01:11:45
谢谢安德烈 R。啊,所以它逐步通过 0 - 2。那么在数学术语中这叫什么?我想我的观点是我从未想过将每个索引除以 index / 2 来获得每个切片的索引。所以我试图将我的头脑围绕它,因为我真的很喜欢它,但在数学方面并没有完全理解它。我通常这样做是为了获得总数的平均值,但这看起来不同。
2021-02-11 01:11:45
这似乎是最简洁的解决方案。什么是 chunkIndex = Math.floor(index/perChunk) ?是平均值吗?
2021-02-15 01:11:45
来自热爱函数式编程的人的热门话题,for 循环比减少到新数组更具可读性
2021-03-06 01:11:45
5/2 = 2.5Math.floor(2.5) = 2因此与索引5项将放置在桶2
2021-03-07 01:11:45

修改自 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]]


次要附录

我应该指出,以上是使用Array.map. 它基本上执行以下操作,其中 ~ 是连接:

[[1,2,3]]~[]~[]~[] ~ [[4,5,6]]~[]~[]~[] ~ [[7]]

它与下面的方法具有相同的渐近运行时间,但由于构建空列表,它可能是一个更糟糕的常数因子。可以将其重写如下(主要与 Blazemonger 的方法相同,这就是我最初没有提交此答案的原因):

更有效的方法:

// 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)
)


我现在首选的方法是上述方法,或以下方法之一:

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));

  }
});

演示:

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

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

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));
}});

或者

Object.defineProperty(Array.prototype, 'chunk', {value: function(n) {
    return Array.from(Array(ceil(this.length/n)), (_,i)=>this.slice(i*n,i*n+n));
}});
@rlemon 给你,这就是这导致的问题。请永远不要修改原生原型,尤其是没有供应商前缀的:developers.google.com/web/updates/2018/03/smooshgate 如果你添加 很好array.myCompanyFlatten,但请不要添加array.flatten并祈祷它永远不会引起问题。如您所见,mootools 多年前的决定现在影响了 TC39 标准。
2021-02-09 01:11:45
呃,我会避免弄乱原型,因为在chunk数组上调用函数所获得的凉爽感并没有真正超过您添加的额外复杂性以及与内置原型混淆可能导致的微妙错误。
2021-02-12 01:11:45
他并没有搞乱它们,而是将它们扩展为数组。我明白从来没有接触过 Object.prototype 因为这会冒泡到所有对象(所有东西),但是对于这个 Array 特定的函数,我没有看到任何问题。
2021-02-18 01:11:45
基于 mozilla 开发站点上的兼容性图表,Array.map for IE9+。当心。
2021-02-25 01:11:45
很肯定这应该是array.map(function(i)没有array.map(function(elem,i),虽然
2021-03-04 01:11:45

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

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

如果您有时间,请观看 Andrew Dupont 在 2011 年的 JSConf 演讲“一切都是允许的:扩展内置函数”,以获得关于这个主题的很好的讨论。

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

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;
“避免使用原生原型” 新的 js 开发人员应该得到一个临时的,如果不是永久的,这句话的纹身。
2021-02-20 01:11:45
@Gherman 我也经常看到这个。我主要在 Laravel 工作,我店里的人倾向于创建各种管理器类以“坚持”OOP,但这样做打破了 Laravel 使项目变得更加复杂的惯例。
2021-02-23 01:11:45
我眼中最好的建议,最容易理解和执行,非常感谢!
2021-02-26 01:11:45
@JacobDalton 我认为这都是大学的错。人们认为 OOP 必须无处不在。所以他们害怕“只是创建一个函数”。他们想确保把它放在什么东西里面。即使它根本不合适。如果没有点符号,就没有“架构”。
2021-02-27 01:11:45
我已经使用 javascript 多年,几乎没有时间花在原型上,最多调用函数,从不像你看到的某些人那样修改。
2021-02-28 01:11:45

我在 jsperf.com 中测试了不同的答案。结果在那里可用:https : //web.archive.org/web/20150909134228/https : //jsperf.com/chunk-mtds

最快的功能(适用于 IE8)是这个:

function chunk(arr, chunkSize) {
  if (chunkSize <= 0) throw "Invalid chunk size";
  var R = [];
  for (var i=0,len=arr.length; i<len; i+=chunkSize)
    R.push(arr.slice(i,i+chunkSize));
  return R;
}
@AymKdn 我不确定,如果返回未修改的数组是最好的错误处理Array<Array>函数的预期返回类型是. 非正的块大小没有任何意义。所以抛出错误对我来说似乎是合理的。
2021-02-08 01:11:45
感谢@AymKdn 制作此基准测试:这很有帮助!我正在使用拼接方法,它使我的 Chrome v70 浏览器崩溃,块大小为 884432。使用您建议的“切片”方法,我的代码不再使浏览器的“渲染”进程崩溃。:)
2021-02-11 01:11:45
需要多长时间chunkSize = 0一些有效的函数输入不应停止进程。
2021-02-12 01:11:45
@ceving 我刚刚在 chunkSize <= 0 时添加了一个条件
2021-02-16 01:11:45
这是一个typescript版本: function chunk<T>(array: T[], chunkSize: number): T[][] { const R = []; for (let i = 0, len = array.length; i < len; i += chunkSize) R.push(array.slice(i, i + chunkSize)); return R; }
2021-03-05 01:11:45