如何仅将一维多维数组的一部分展平?

时间:2018-04-28 02:23:33

标签: javascript arrays json multidimensional-array flatten

我有一个复杂的JSON对象。我正在尝试处理它以创建一个看起来像这样的数组:

[
    [ "Name", "Spec", "Spec" ],
    [ "Name", "Spec", "Spec" ]
]

这是我被困的地方:

let array = products.map((product) => {
    return [
        product.name,
        product.attributes
            .map((attribute) => (
                attribute.spec
            ))
            .reduce((accumulator, currentValue) => {
                return accumulator.concat(currentValue);
            }, [])
    ];
});

结果如下:

[
    [ "Name", [ "Spec", "Spec" ] ],
    [ "Name", [ "Spec", "Spec" ] ]
]

不可否认,我并不完全理解reduce方法及其initialValue参数。我知道使用该方法可以在map的顶级使用中展平数组,但在更深层次上,似乎什么都不做。

我在线搜索但是只找到了涉及完全展平深度数组的答案。由于缺乏兼容性,flatten()方法不是一种选择。

有人可以建议如何仅限二级吗?如果可能的话,我想通过改变数组来实现这一目标。

2 个答案:

答案 0 :(得分:1)

你不需要那里的减速器 - 它只是让事情变得不必要地变得复杂。将attributes映射到其spec属性,然后使用spread:

const array = products.map(({ name, attributes }) => {
  const specs = attributes.map(attribute => attribute.spec);
  return [name, ...specs];
});

答案 1 :(得分:1)

1。为什么这会失败?

您将reduce放在错误的位置。你正在扁平化规格列表,这已经是一个扁平阵列。您想要展平具有名称和规范列表的列表。这是一种可能性:

const array = products.map(prod => [
  prod.name,
  prod.attributes.map(attr => attr.spec)
].reduce((acc, curr) => acc.concat(curr), []));

2。什么是更好的解决方案?

正如CertainPerformance指出的那样,有一个更简单的版本,我可能会稍微改写一下

const array = products.map(({name, attributes}) =>
  [name, ...attributes.map(attr => attr.spec)]
);

3。如果我需要在其他地方重用flatten该怎么办?

从第一个解决方案中提取它作为可重用的函数。这不是新Array flatten方法的完全替代品,但它可能就是您所需要的:

const flatten = arr => arr.reduce((acc, curr) => acc.concat(curr), [])

const array = products.map(prod => flatten([
    prod.name,
    prod.attributes.map(attr => attr.spec)
  ])
)

4。 reduce调用如何平整一个级别?

我们可以将[x, y, z].reduce(fn, initial)视为执行这些步骤

  1. 致电fn(initial, x),产生价值a
  2. 致电fn(a, y),产生价值b
  3. 致电fn(b, z),产生价值c
  4. 由于数组已耗尽,因此返回值c
  5. 换句话说,[x, y, z].reduce(fn, initial)会返回fn(fn(fn(initial, x), y), z)

    fn(acc, val) => acc.concat(val)时,我们可以将['name', ['spec1', 'spec2']].reduce(fn, [])视为fn(fn([], 'name'), ['spec1', 'spec2']),这与([].concat('name')).concat(['spec1', 'spec2'])相同,当然是['name', 'spec1', 'spec2'] {1}}。

    5。我的问题有什么问题吗?

    我很高兴你问。 : - )

    有一次重大失败。您没有包含任何样本数据。要解决此问题,需要尝试从代码中重建数据格式。给出一个最小的例子很简单,例如:

    const products = [
      {name: 'foo', attributes: [{spec: 'bar'}, {spec: 'baz'}]},
      {name: 'oof', attributes: [{spec: 'rab'}, {spec: 'zab'}]}
    ]
    

    具有匹配的预期输出:

    [
      ["foo", "bar", "baz"], 
      ["oof", "rab", "zab"]
    ]
    

    6。我的输出结构怎么样?

    现在你提到它,这似乎是一个奇怪的结构。你可能有充分的理由,但这很奇怪。

    数组通常在Javascript中有两个用途。它们是相同类型的元素的任意长度列表,或者它们是固定长度列表,每个索引都有特定类型(又名元组。)

    但是你的结构结合了这两者。它们是任意的 - (至少看起来如此)长度列表,其中第一个条目是名称,后续条目是规格。虽然可能有理由这样做,但您可能需要考虑这种结构是否特别有用。

    7。如何在不改变的情况下做到这一点?

      

    如果可能的话,我想通过改变数组来实现这一目标。

    我拒绝参加这样的恐怖事件。

    但是,严肃地说,不可变数据使得编码更容易。您是否有任何真正的理由将其列为要求?