【问题标题】:Split array into different size chunks (4, 3, 3, 3, 4, 3, 3, 3, etc)将数组拆分为不同大小的块(4、3、3、3、4、3、3、3 等)
【发布时间】: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
    ]
]

【问题讨论】:

    标签: javascript arrays multidimensional-array ecmascript-6 reduce


    【解决方案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);

        【讨论】:

          猜你喜欢
          • 2021-07-04
          • 2021-03-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-11-09
          相关资源
          最近更新 更多