按两个属性对对象数组进行分组

huangapple go评论92阅读模式
英文:

Group array of objects by two properties

问题

我尝试通过两个属性将对象数组分组,以便在两个级别获取数据。这是在JavaScript - Node服务器中进行的操作。这是我要处理的数据:

  1. items = [
  2. {month: 11, year: 2022, amount: 10},
  3. {month: 12, year: 2022, amount: 6},
  4. {month: 11, year: 2022, amount: 7},
  5. {month: 12, year: 2022, amount: 12},
  6. {month: 1, year: 2023, amount: 5},
  7. {month: 1, year: 2023, amount: 15},
  8. {month: 11, year: 2023, amount: 30},
  9. {month: 11, year: 2023, amount: 20}
  10. ]

我需要将同一年和同一月的所有项目分组在一起。最终结果将如下所示:

  1. result = {
  2. "2022": {
  3. "11": [
  4. {month: 11, year: 2022, amount: 10},
  5. {month: 11, year: 2022, amount: 7}
  6. ],
  7. "12": [
  8. {month: 12, year: 2022, amount: 6},
  9. {month: 12, year: 2022, amount: 12}
  10. ]
  11. },
  12. "2023": {
  13. "11": [
  14. {month: 11, year: 2023, amount: 30},
  15. {month: 11, year: 2023, amount: 20}
  16. ],
  17. "1": [
  18. {month: 1, year: 2023, amount: 5},
  19. {month: 1, year: 2023, amount: 15}
  20. ]
  21. }
  22. }

第一步很容易完成,可以使用reduce或groupBy(),我选择了groupBy()因为它更清晰:

  1. const itemsPerYear = items.groupBy(item => { return item.year })

这给我一个中间结果:

  1. itemsPerYear = {
  2. "2022": [
  3. {month: 11, year: 2022, amount: 10},
  4. {month: 11, year: 2022, amount: 7},
  5. {month: 12, year: 2022, amount: 6},
  6. {month: 12, year: 2022, amount: 12}
  7. ],
  8. "2023": [
  9. {month: 11, year: 2023, amount: 30},
  10. {month: 11, year: 2023, amount: 20},
  11. {month: 1, year: 2023, amount: 5},
  12. {month: 1, year: 2023, amount: 15}
  13. ]
  14. }

所以,如果我应用类似的逻辑并执行:

  1. const itemsPerMonth = Object.values(itemsPerYear).groupBy(item => { return item.month })

我得到以下结果:

  1. [Object: null prototype] {
  2. undefined: [
  3. [ [Object], [Object], [Object], [Object] ],
  4. [ [Object], [Object], [Object], [Object] ]
  5. ]
  6. }

通过使用forEach(),我离目标更近一步:

  1. const itemsPerMonth = Object.values(itemsPerYear).forEach(sub => { console.log(sub) })

这给我:

  1. [
  2. {month: 11, year: 2022, amount: 10},
  3. {month: 11, year: 2022, amount: 7},
  4. {month: 12, year: 2022, amount: 6},
  5. {month: 12, year: 2022, amount: 12}
  6. ],
  7. [
  8. {month: 11, year: 2023, amount: 30},
  9. {month: 11, year: 2023, amount: 20},
  10. {month: 1, year: 2023, amount: 5},
  11. {month: 1, year: 2023, amount: 15}
  12. ]

如果我想在forEach()内部使用groupBy(),我得到undefined。

谢谢。

英文:

I'm trying to group array of objects by two properties so I get data on two levels. This is in JavaScript - Node server.
Here is the data I'm starting with

  1. items = [
  2. {month: 11, year: 2022, amount: 10},
  3. {month: 12, year: 2022, amount: 6},
  4. {month: 11, year: 2022, amount: 7},
  5. {month: 12, year: 2022, amount: 12},
  6. {month: 1, year: 2023, amount: 5},
  7. {month: 1, year: 2023, amount: 15},
  8. {month: 11, year: 2023, amount: 30},
  9. {month: 11, year: 2023, amount: 20}
  10. ],

I need all items from the same month and in the same year grouped together. The final result would look like this:

  1. result = {
  2. "2022": {
  3. "11": [
  4. {month: 11, year: 2022, amount: 10},
  5. {month: 11, year: 2022, amount: 7}
  6. ],
  7. "12": [
  8. {month: 12, year: 2022, amount: 6},
  9. {month: 12, year: 2022, amount: 12}
  10. ]
  11. },
  12. "2023": {
  13. "11": [
  14. {month: 11, year: 2023, amount: 30},
  15. {month: 11, year: 2023, amount: 20}
  16. ],
  17. "1": [
  18. {month: 1, year: 2023, amount: 5},
  19. {month: 1, year: 2023, amount: 15}
  20. ]
  21. }
  22. }

The first step is done quite easily, either through reduce or groupBy(), I've opted for groupBy() because it is cleaner:

  1. const itemsPerYear = items.groupBy(item => { return item.year })

This gives me intermediate result:

  1. itemsPerYear = {
  2. "2022": [
  3. {month: 11, year: 2022, amount: 10},
  4. {month: 11, year: 2022, amount: 7},
  5. {month: 12, year: 2022, amount: 6},
  6. {month: 12, year: 2022, amount: 12}
  7. ],
  8. "2023": [
  9. {month: 11, year: 2023, amount: 30},
  10. {month: 11, year: 2023, amount: 20},
  11. {month: 1, year: 2023, amount: 5},
  12. {month: 1, year: 2023, amount: 15}
  13. ]
  14. }

So if I apply similar logic and go with:

  1. const itemsPerMonth = Object.values(itemsPerYear).groupBy(item => { return item.month })

I get:

  1. [Object: null prototype] {
  2. undefined: [
  3. [ [Object], [Object], [Object], [Object] ],
  4. [ [Object], [Object], [Object], [Object] ]
  5. ]
  6. }

I get a step closer with ForEach:
const itemsPerMonth = Object.values(itemsPerYear).forEach(sub => { console.log(sub) })
I get:

  1. [
  2. {month: 11, year: 2022, amount: 10},
  3. {month: 11, year: 2022, amount: 7},
  4. {month: 12, year: 2022, amount: 6},
  5. {month: 12, year: 2022, amount: 12}
  6. ],
  7. [
  8. {month: 11, year: 2023, amount: 30},
  9. {month: 11, year: 2023, amount: 20},
  10. {month: 1, year: 2023, amount: 5},
  11. {month: 1, year: 2023, amount: 15}
  12. ]

If I want to use groupBy() inside the ForEach() I get undefined.

Thanks

答案1

得分: 4

以下是使用.reduce()的快速解决方案:

  1. const input = [ {month: 11, year: 2022, amount: 10}, {month: 12, year: 2022, amount: 6}, {month: 11, year: 2022, amount: 7}, {month: 12, year: 2022, amount: 12}, {month: 1, year: 2023, amount: 5}, {month: 1, year: 2023, amount: 15}, {month: 11, year: 2023, amount: 30}, {month: 11, year: 2023, amount: 20} ];
  2. const result = input.reduce((acc, obj) => {
  3. if(!acc[obj.year]) acc[obj.year] = {};
  4. if(!acc[obj.year][obj.month]) acc[obj.year][obj.month] = [];
  5. acc[obj.year][obj.month].push(obj);
  6. return acc;
  7. }, {});
  8. console.log('result:', result);

文档:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

英文:

Here is a quick solution using a .reduce():

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

  1. const input = [ {month: 11, year: 2022, amount: 10}, {month: 12, year: 2022, amount: 6}, {month: 11, year: 2022, amount: 7}, {month: 12, year: 2022, amount: 12}, {month: 1, year: 2023, amount: 5}, {month: 1, year: 2023, amount: 15}, {month: 11, year: 2023, amount: 30}, {month: 11, year: 2023, amount: 20} ];
  2. const result = input.reduce((acc, obj) =&gt; {
  3. if(!acc[obj.year]) acc[obj.year] = {};
  4. if(!acc[obj.year][obj.month]) acc[obj.year][obj.month] = [];
  5. acc[obj.year][obj.month].push(obj);
  6. return acc;
  7. }, {});
  8. console.log(&#39;result:&#39;, result);

<!-- end snippet -->

Docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

huangapple
  • 本文由 发表于 2023年2月6日 07:07:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/75356124.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定