JavaScript:如何将具有嵌套属性的对象数组分组?

标签 javascript ecmascript-6 lodash reduce

我有这个对象数组:

[
  {
    "date": "08/08/2022",
    "name": "Swordsman",
    "items": [
      {
        "item_id": 1,
        "item": {
          "item_name": "Item 1",
        },
        "count": 1
      }
    ]
  },
  {
    "date": "08/08/2022",
    "name": "Swordsman",
    "items": [
      {
        "item_id": 1,
        "item": {
          "item_name": "Item 1",
        },
        "count": 2
      },
      {
        "item_id": 2,
        "item": {
          "item_name": "Item 2",
        },
        "count": 1
      }
    ]
  }
]

我想要实现的是按日期名称项目数量分组。期望的结果是:

[
  {
    "date": "08/08/2022",
    "name": "Swordsman",
    "items": [
      {
        "item_id": 1,
        "name": "Item 1",
        "count": 3
      },
      {
        "item_id": 2,
        "name": "Item 2",
        "count": 1
      }
    ]
  }
]

如果日期相同,但名称不同,例如:

[
  {
    "date": "08/08/2022",
    "name": "Swordsman",
    "items": [
      {
        "item_id": 1,
        "item": {
          "item_name": "Item 1",
        },
        "count": 1
      }
    ]
  },
  {
    "date": "08/08/2022",
    "name": "Swordsman",
    "items": [
      {
        "item_id": 1,
        "item": {
          "item_name": "Item 1",
        },
        "count": 2
      },
      {
        "item_id": 2,
        "item": {
          "item_name": "Item 2",
        },
        "count": 1
      }
    ]
  },
  {
    "date": "08/08/2022",
    "name": "Archer",
    "items": [
      {
        "item_id": 1,
        "item": {
          "item_name": "Item 1",
        },
        "count": 2
      },
      {
        "item_id": 2,
        "item": {
          "item_name": "Item 2",
        },
        "count": 1
      }
    ]
  }
]

期望的结果是:

[
  {
    "date": "08/08/2022",
    "name": "Swordsman",
    "items": [
      {
        "item_id": 1,
        "name": "Item 1",
        "count": 3
      },
      {
        "item_id": 2,
        "name": "Item 2",
        "count": 1
      }
    ]
  },
  {
    "date": "08/08/2022",
    "name": "Archer",
    "items": [
      {
        "item_id": 1,
        "name": "Item 1",
        "count": 2
      },
      {
        "item_id": 2,
        "name": "Item 2",
        "count": 1
      }
    ]
  }
]

我尝试过使用lodash和数组reduce方法,但仍然无法得到想要的结果:

const groups = data.reduce((groups, data) => {
  const date = data.date;
  if (!groups[date]) {
    groups[date] = [];
  }
  
  groups[date].push(data);
  return groups;
}, {});

const groupArrays = Object.keys(groups).map((date) => {
  return {
    date,
    items: groups[date]
  };
});

如何实现这一目标?需要您的投入。谢谢!

最佳答案

您可以通过以下方式实现:

const arr = [
    {
        date: '08/08/2022',
        name: 'Swordsman',
        items: [
            {
                item_id: 1,
                item: {
                    item_name: 'Item 1',
                },
                count: 1,
            },
        ],
    },
    {
        date: '08/08/2022',
        name: 'Swordsman',
        items: [
            {
                item_id: 1,
                item: {
                    item_name: 'Item 1',
                },
                count: 2,
            },
            {
                item_id: 2,
                item: {
                    item_name: 'Item 2',
                },
                count: 1,
            },
        ],
    },
    {
        date: '08/08/2022',
        name: 'Archer',
        items: [
            {
                item_id: 1,
                item: {
                    item_name: 'Item 1',
                },
                count: 2,
            },
            {
                item_id: 2,
                item: {
                    item_name: 'Item 2',
                },
                count: 1,
            },
        ],
    },
];

function addItemsToNewArrFromOld(oldItems, newItemsToAdd) {
    newItemsToAdd.forEach((o) => {
        const { item_id, count, item: { item_name: item }} = o;
        const itemInOldItems = oldItems.find((obj) => obj.item_id === o.item_id);
        if (itemInOldItems) itemInOldItems.count += o.count;
        else oldItems.push({ item_id, count, item });
    });
}

const map = new Map();
arr.forEach(({ date, name, items }) => {
    const key = `${date}-${name}`;

    if (map.has(key)) {
        const objForKeyFound = map.get(key);
        addItemsToNewArrFromOld(objForKeyFound.items, items);
    } else {
        map.set(key, {
            date, name, items: items.map(({ item_id, item, count }) => ({ item_id, count, item: item.item_name })),
        });
    }
});

const result = [...map.values()];
console.log(result);

关于JavaScript:如何将具有嵌套属性的对象数组分组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73433299/

相关文章:

javascript - Lodash _.some 不工作

javascript - 使用属性名称在 javascript 中查找对象的索引

javascript - 无论屏幕高度/宽度如何,如何使图像停留在屏幕底部?

javascript - 如何使用 lodash 的 ._get 方法检查路径的 2 个值

javascript - 在 ES6/TS 中通过 mutate 将对象设置为 null 以匹配 Set 中的条件

javascript - 发布 NPM 包时,我得到一个空对象,我的设置是 (ES6,Babel,Webpack,React,Redux,Sagas)

javascript - 如何使用 lodash 按单个属性过滤/比较 2 个对象数组?

javascript - 使用 PageAsyncTask 在页面上调用 javascript 代码

javascript - 如果 Node.js 中发生错误,则重复函数

javascript - 如何在 Promises 上冒泡错误而不在每个级别调用 `catch`?