将数组拆分为不同大小的块(4、3、3、3、4、3、3、3 等)

Posted

技术标签:

【中文标题】将数组拆分为不同大小的块(4、3、3、3、4、3、3、3 等)【英文标题】:Split array into different size chunks (4, 3, 3, 3, 4, 3, 3, 3, etc) 【发布时间】:2020-05-30 13:49:43 【问题描述】:

我有一个这样的数组:[1, 2, 3, 4, 5, 6, 7, 9, 10]。我需要将它分成不同大小的块,但使用一个简单的模式:4、3、3、3、4、3、3、3,如下所示:

[
    [ // four
        1,
        2,
        3,
        4
    ],
    [ // three (1/3)
        5,
        6,
        7
    ],
    [ // three (2/3)
        8,
        9,
        10
    ],
    [ // three (3/3)
        11,
        12,
        13
    ],
    [ // four
        14,
        15,
        16,
        17
    ],
    [ // three (1/3)
        18,
        19,
        20
    ], // and so on..
]

我已经尝试使用我自定义的这段代码:

const arr; // my array of values
const chuncked = arr.reduce((acc, product, i) => 
    if (i % 3) 
        return acc;
     else if (!didFourWayReduce) 
        didFourWayReduce = true;
        fourWayReduces++;

        if ((fourWayReduces - 1) % 2)  // only make every second a "4 row"
            return [...acc, arr.slice(i, i + 3)];
         else 
            return [...acc, arr.slice(i, i + 4)];
        
     else 
        didFourWayReduce = false;
        return [...acc, arr.slice(i, i + 3)];
    
, []);

并且它几乎可以工作,期望第一个三块(1/3)具有该块的最后一个元素为 4。因此,每三个的第一个块重复 1 个键。像这样:

[
    [
        1,
        2,
        3,
        4
    ],
    [
        4, // this one is repeated, and it shouldn't be
        5,
        6
    ]
]

【问题讨论】:

【参考方案1】:

您可以使用两个索引,一个用于数据数组,一个用于大小。然后以给定长度对数组进行切片并将块推送到块数组。

继续直到数据结束。

var data = Array.from( length: 26 , (_, i) => i + 1),
    sizes = [4, 3, 3, 3],
    i = 0,
    j = 0,
    chunks = [];

while (i < data.length) chunks.push(data.slice(i, i += sizes[j++ % sizes.length]));

console.log(chunks);
.as-console-wrapper  max-height: 100% !important; top: 0; 

【讨论】:

太美了。可以对其进行调整,使其适用于无限长的数组吗?我看到你定义了固定的长度和尺寸。 如果 sizesj 的模式已经可以工作,余数为 sizes 的长度。 爱你的技能尼娜。难以置信你做的这么短!!【参考方案2】:

const arr = Array.from( length: 100 , (_, i) => i);

const copy = [...arr];

const sizes = [4, 3, 3, 3];

const result = [];

let i = 0;

while (i <= arr.length && copy.length) 
  result.push(copy.splice(0, sizes[i % sizes.length]));
  i++;


console.log(result);

【讨论】:

【参考方案3】:

递归方法相当优雅:

const chunks = (xs, [s, ...ss]) =>
  xs.length ? [xs .slice (0, s), ... chunks (xs .slice (s), [...ss, s])] : []

const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
const sizes = [4, 3, 3, 3]

console .log (chunks (data, sizes))
.as-console-wrapper  max-height: 100% !important; top: 0; 

通过将[s, ...ss] 替换为[...ss, s],我们传递了sizes 数组的循环版本,例如,[4, 3, 3, 3] 变为[3, 3, 3, 4]。这使得逐步解析变得容易。

【讨论】:

@NinaScholz:是的,没有人说这是高性能的,只有优雅。我们当然可以编写一个仅适用于索引的类似版本,但它可能不那么诱人。 例如const chunks = (xs, ss, i = 0, j = 0) =&gt; i &lt; xs.length ? [xs .slice (i, i + ss[j]), ... chunks (xs, ss, i + ss[j], (j + 1) % ss.length)] : []【参考方案4】:

Mod 运算符检查它应该是 4 还是 3。使用两个数组只是为了使它更容易(可以用一个来完成)

const groupIt = arr => arr.reduce((
  group,
  out
, v, i) => 
  var max = out.length % 4 === 0 ? 4 : 3
  group.push(v)
  if (group.length === max || i === arr.length - 1) 
    out.push(group)
    group = []
  
  return 
    group,
    out
  
, 
  group: [],
  out: []
).out

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

var test = (new Array(30)).fill(0).map((x,i) => i + 1)
console.log(groupIt(test))

只有一个:

const groupIt = arr => arr.reduce((out, v, i) => 
  var max = (out.length - 1) % 4 === 0 ? 4 : 3
  out[out.length - 1].push(v)
  if (out[out.length - 1].length === max) 
    out.push([])
  
  return out
, [[]])

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

var test = (new Array(30)).fill(0).map((x, i) => i + 1)
console.log(groupIt(test))

【讨论】:

【参考方案5】:

这个答案和Nina Scholz的答案类似,但是使用了一个for循环,我个人觉得比较清楚。

const arr = Array.from(length: 100, (_, i) => i + 1);
const sizes = [4, 3, 3, 3];
const result = [];

for (let i = 0, j = 0; i < arr.length; i += sizes[j], j = (j + 1) % sizes.length) 
  result.push(arr.slice(i, i + sizes[j]));


console.log(result);

【讨论】:

以上是关于将数组拆分为不同大小的块(4、3、3、3、4、3、3、3 等)的主要内容,如果未能解决你的问题,请参考以下文章

拆分、分组和均值:使用数组计算

将一个 JS 数组拆分为 N 个数组

将数组拆分为具有最小块大小的给定大小的块

怎么把一个数组拆分为两个啊,如a=1,2,3,4,5,6,7拆分后为a=1,2,7b=3

将数组拆分为给定大小的块[重复]

javascript 将数组拆分为相同大小的块