简体   繁体   English

如何将对象数组拆分为块

[英]How to split array of objects into chunks

Im trying to split my array of 9 elements into array of 3 arrays, each with 3 elements.我试图将我的 9 个元素数组拆分为 3 个数组的数组,每个数组有 3 个元素。

 const data = [{ name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, ]; const chunks = Array(3).fill(Array()); data.forEach((value, index) => chunks[index % chunks.length].push(value)); console.log(chunks);

I can't understand why it's producing array of 3 arrays with 9 elements in each.我不明白为什么它会生成 3 个数组,每个数组有9 个元素。

Whats is wrong with chunks[index%chunks.length].push(value) ? chunks[index%chunks.length].push(value)什么问题?

This happens because fill is returning the same array to each element, hence pushing to either of the three is, in fact, pushing to the same reference.发生这种情况是因为fill向每个元素返回相同的数组,因此推入三个中的任何一个实际上是推入相同的引用。

Mentioned in the MDN docs:在 MDN 文档中提到:

The fill() method fills (modifies) all the elements of an array from a start index (default zero) to an end index (default array length) with a static value. fill() 方法使用静态值填充(修改)数组从开始索引(默认为零)到结束索引(默认数组长度)的所有元素。 It returns the modified array.它返回修改后的数组。

^-- a STATIC value. ^--静态值。 Read more about fill here 在此处阅读有关填充的更多信息

To make it clearer, this:为了更清楚,这个:

const chunks = Array(3).fill(Array());

can be "interpreted" as this:可以“解释”为:

const chunks = new Array(3);
var arr = new Array();
for (var i = 0; i < chunks.length; i++) chunks.push(arr);

So, basically, the same reference of the array is pushed to the original array;因此,基本上,数组的相同引用被推送到原始数组; hence, altering arr means altering all the references of it, so all the references in chunks are pointing to the same array, so all are "altered", meaning they all will point to the same array and share the same values.因此,改变arr意味着改变它的所有引用,所以chunks中的所有引用都指向同一个数组,所以都被“改变”了,这意味着它们都将指向同一个数组并共享相同的值。

You can solve that in many ways, the fastest I can think of is using Array.from as done below, where the callback returns a new array everytime.您可以通过多种方式解决这个问题,我能想到的最快的方法是使用Array.from如下所示,回调每次都返回一个数组。

 const data = [ { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, ]; const chunks = Array.from({length: 3}, (_) => []); data.forEach((value, index) => chunks[index%chunks.length].push(value)); console.log(chunks);

Relevant code explanation相关代码说明

Array.from({length: 3}, (_) => []);

  • Array.from creates a new array from the defined properties list. Array.from 从定义的属性列表中创建一个新数组。 in this case, it creates a new array with length 3.在这种情况下,它会创建一个长度为 3 的新数组。
  • (_) => [] is the callback invoked to assign the value of each element of the array. (_) => []是调用回调来分配数组每个元素的值。 In that case, I'm just returning a new array.在那种情况下,我只是返回一个数组。 This could also be shortened to: () => []这也可以缩短为: () => []

And that's it.就是这样。

Just in case, you might be interested in solution that may work 3 times faster , check out my approach:以防万一,您可能对速度提高 3 倍的解决方案感兴趣,请查看我的方法:

 const data=[{name:'a',surname:'b'},{name:'a',surname:'b'},{name:'a',surname:'b'},{name:'a',surname:'b'},{name:'a',surname:'b'},{name:'a',surname:'b'},{name:'a',surname:'b'},{name:'a',surname:'b'},{name:'a',surname:'b'},]; const chunkArr = (arr, size) => arr.reduceRight((r,i,_,s) => (r.push(s.splice(0,size)),r),[]); console.log(chunkArr(data,3));
 .as-console-wrapper {min-height: 100%}

You could slice the array by the index and the wanted size.您可以按索引和所需大小对数组进行切片。

 var data = [{ name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }], chunks = [], size = 3, i = 0; while (i < data.length) chunks.push(data.slice(i, i += size)); console.log(chunks);
 .as-console-wrapper { max-height: 100% !important; top: 0; }

const chunks = Array(3).fill(Array());

You have filled the chunks array with 3 times the same array object.您已经用 3 次相同的数组对象填充了 chunks 数组。 Spelled out:拼写:

const chunk = Array();
const chunks = Array(3).fill(chunk);

Which basically ends up being called in forEach:基本上最终在 forEach 中被调用:

data.forEach((value, index) => chunk.push(value));

Change it to:将其更改为:

const chunks = Array(3).fill(1).map(() => []);

For me, a more visual solution is using the Array.from() method:对我来说,更直观的解决方案是使用Array.from()方法:

const arr = [{ name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }, { name: 'a', surname: 'b' }];
    
const resulr = Array.from({length: 3}, (_, i) => arr.slice(i * 3, (i + 1) * 3));

// Or a common solution:

const chunk = (arr, l) => Array.from({length: Math.ceil(arr.length/l)}, (_, i) => arr.slice(i * l, (i + 1) * l));

console.log(resulr);
console.log(chunk(arr, 3));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM