【问题标题】:Reduce data into nested categories将数据减少到嵌套类别
【发布时间】:2021-10-06 07:50:24
【问题描述】:

我正在尝试将数据数组减少为嵌套对象。除了下一个项目,我几乎拥有它。它不会推入数组,而是覆盖整个数组本身,只留下 1 个值。

我 100% 确定问题出在这行代码 [...(acc[t.sub_region] || []), t] 我的直觉告诉我我需要按照 [...(acc[t.region][t.sub_region] || []), t] 的方式做一些事情,但是当我尝试这个时它出错了。

我在下面发布了一个 sn-p,您可以看到 SOUTH_EUROPE 在其数组中只有 1 个项目,而它应该有 2 个。

期望的结果

const sorted = {
    EUROPE: {
        SOUTH_EUROPE: [{ item: 'Item 1' }, { item: 'Item 2' }],
        NORTH_EUROPE: [{ item: 'Item 3' }],
    },
    AMERICAS: {
        NORTH_AMERICA: [{ item: 'Item 4' }],
    },
}

const items = [
    {
        region: 'EUROPE',
        sub_region: 'SOUTH_EUROPE',
        item: 'Item 1'
    },
    {
        region: 'EUROPE',
        sub_region: 'SOUTH_EUROPE',
        item: 'Item 2'
    },
    {
        region: 'EUROPE',
        sub_region: 'NORTH_EUROPE',
        item: 'Item 3'
    },
    {
        region: 'AMERICAS',
        sub_region: 'NORTH_AMERCA',
        item: 'Item 4'
    },
]

const sorted = items.reduce((acc, t) => {
    return {
        ...acc,
        [t.region]: {
            ...acc[t.region],
            [t.sub_region]: [...(acc[t.sub_region] || []), t],
        },
    }
}, {})

console.log(sorted)

【问题讨论】:

  • 如果这是生产代码,我强烈建议使用循环。我相信这个功能将很难调试/维护。使用简单的 for 循环可以消除一些不必要的复杂性
  • @VincentMenzel 我不同意在这种情况下使用循环与减少。我同意这可能会让不熟悉 reduce 功能但可以通过几行文档得到支持的人感到困惑。如果您想向我展示一个使用循环的更简单的解决方案,我很乐意看看

标签: javascript reduce


【解决方案1】:

sub_region 是一个嵌套属性,所以你需要使用acc?.[t.region]?.[t.sub_region] 来访问它。请注意,optional chaining operator 用于防止在该区域尚不存在时引发错误。

const items = [
    {
        region: 'EUROPE',
        sub_region: 'SOUTH_EUROPE',
        item: 'Item 1'
    },
    {
        region: 'EUROPE',
        sub_region: 'SOUTH_EUROPE',
        item: 'Item 2'
    },
    {
        region: 'EUROPE',
        sub_region: 'NORTH_EUROPE',
        item: 'Item 3'
    },
    {
        region: 'AMERICAS',
        sub_region: 'NORTH_AMERCA',
        item: 'Item 4'
    },
]

const sorted = items.reduce((acc, t) => {
    return {
        ...acc,
        [t.region]: {
            ...acc[t.region],
            [t.sub_region]: [...(acc?.[t.region]?.[t.sub_region] || []),
                              {item: t.item}],
        },
    }
}, {})

console.log(sorted)

【讨论】:

    【解决方案2】:

    跟进我的评论,推荐一个更易于管理但“不太干净”的 for 循环。无论如何,我推荐 for 循环的原因是,根据我的经验,没有多少开发人员对 reduce 函数有广泛的了解,特别是如果您的团队中有初级开发人员。但是我同意好的文档也可以提供必要的信息来维护它。但是,您在阅读函数时无法快速理解该函数,这通常意味着变量名称无信息、过于复杂或缺少文档。

    const items = [{
        region: 'EUROPE',
        sub_region: 'SOUTH_EUROPE',
        item: 'Item 1'
      },
      {
        region: 'EUROPE',
        sub_region: 'SOUTH_EUROPE',
        item: 'Item 2'
      },
      {
        region: 'EUROPE',
        sub_region: 'NORTH_EUROPE',
        item: 'Item 3'
      },
      {
        region: 'AMERICAS',
        sub_region: 'NORTH_AMERCA',
        item: 'Item 4'
      },
    ]
    
    const categorize = (someItems) => {
      const sorted = {}
      someItems.forEach(item => {
        if (!sorted[item.region]) sorted[item.region] = {}
        if (!sorted[item.region][item.sub_region]) sorted[item.region][item.sub_region] = []
    
        sorted[item.region][item.sub_region].push(item)
      })
      return sorted
    }
    
    console.log(categorize(items))

    【讨论】:

    • 感谢 Vincent 的跟进。我没想到它会像你介绍的那样干净,干得好。我很想知道一个是否比另一个更高效,但可能会根据我所合作的团队类型而牢记这种结构。
    • 首先感谢您的友好反馈。我让这两个函数运行 100.000 次。我的解决方案花费了大约 52 毫秒,而 reduce 函数花费了大约 260 毫秒,但这可能是由于我弄乱的方式。这是我的控制台截图作为参考i.prnt.sc/jDTt7F2LQo_V_bQOBW-TEg.png
    猜你喜欢
    • 1970-01-01
    • 2018-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-20
    • 1970-01-01
    • 2018-01-12
    • 2019-12-21
    相关资源
    最近更新 更多