英文:
Group array of objects by two properties
问题
我尝试通过两个属性将对象数组分组,以便在两个级别获取数据。这是在JavaScript - Node服务器中进行的操作。这是我要处理的数据:
items = [
{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}
]
我需要将同一年和同一月的所有项目分组在一起。最终结果将如下所示:
result = {
"2022": {
"11": [
{month: 11, year: 2022, amount: 10},
{month: 11, year: 2022, amount: 7}
],
"12": [
{month: 12, year: 2022, amount: 6},
{month: 12, year: 2022, amount: 12}
]
},
"2023": {
"11": [
{month: 11, year: 2023, amount: 30},
{month: 11, year: 2023, amount: 20}
],
"1": [
{month: 1, year: 2023, amount: 5},
{month: 1, year: 2023, amount: 15}
]
}
}
第一步很容易完成,可以使用reduce或groupBy(),我选择了groupBy()因为它更清晰:
const itemsPerYear = items.groupBy(item => { return item.year })
这给我一个中间结果:
itemsPerYear = {
"2022": [
{month: 11, year: 2022, amount: 10},
{month: 11, year: 2022, amount: 7},
{month: 12, year: 2022, amount: 6},
{month: 12, year: 2022, amount: 12}
],
"2023": [
{month: 11, year: 2023, amount: 30},
{month: 11, year: 2023, amount: 20},
{month: 1, year: 2023, amount: 5},
{month: 1, year: 2023, amount: 15}
]
}
所以,如果我应用类似的逻辑并执行:
const itemsPerMonth = Object.values(itemsPerYear).groupBy(item => { return item.month })
我得到以下结果:
[Object: null prototype] {
undefined: [
[ [Object], [Object], [Object], [Object] ],
[ [Object], [Object], [Object], [Object] ]
]
}
通过使用forEach(),我离目标更近一步:
const itemsPerMonth = Object.values(itemsPerYear).forEach(sub => { console.log(sub) })
这给我:
[
{month: 11, year: 2022, amount: 10},
{month: 11, year: 2022, amount: 7},
{month: 12, year: 2022, amount: 6},
{month: 12, year: 2022, amount: 12}
],
[
{month: 11, year: 2023, amount: 30},
{month: 11, year: 2023, amount: 20},
{month: 1, year: 2023, amount: 5},
{month: 1, year: 2023, amount: 15}
]
如果我想在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
items = [
{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}
],
I need all items from the same month and in the same year grouped together. The final result would look like this:
result = {
"2022": {
"11": [
{month: 11, year: 2022, amount: 10},
{month: 11, year: 2022, amount: 7}
],
"12": [
{month: 12, year: 2022, amount: 6},
{month: 12, year: 2022, amount: 12}
]
},
"2023": {
"11": [
{month: 11, year: 2023, amount: 30},
{month: 11, year: 2023, amount: 20}
],
"1": [
{month: 1, year: 2023, amount: 5},
{month: 1, year: 2023, amount: 15}
]
}
}
The first step is done quite easily, either through reduce or groupBy(), I've opted for groupBy() because it is cleaner:
const itemsPerYear = items.groupBy(item => { return item.year })
This gives me intermediate result:
itemsPerYear = {
"2022": [
{month: 11, year: 2022, amount: 10},
{month: 11, year: 2022, amount: 7},
{month: 12, year: 2022, amount: 6},
{month: 12, year: 2022, amount: 12}
],
"2023": [
{month: 11, year: 2023, amount: 30},
{month: 11, year: 2023, amount: 20},
{month: 1, year: 2023, amount: 5},
{month: 1, year: 2023, amount: 15}
]
}
So if I apply similar logic and go with:
const itemsPerMonth = Object.values(itemsPerYear).groupBy(item => { return item.month })
I get:
[Object: null prototype] {
undefined: [
[ [Object], [Object], [Object], [Object] ],
[ [Object], [Object], [Object], [Object] ]
]
}
I get a step closer with ForEach:
const itemsPerMonth = Object.values(itemsPerYear).forEach(sub => { console.log(sub) })
I get:
[
{month: 11, year: 2022, amount: 10},
{month: 11, year: 2022, amount: 7},
{month: 12, year: 2022, amount: 6},
{month: 12, year: 2022, amount: 12}
],
[
{month: 11, year: 2023, amount: 30},
{month: 11, year: 2023, amount: 20},
{month: 1, year: 2023, amount: 5},
{month: 1, year: 2023, amount: 15}
]
If I want to use groupBy() inside the ForEach() I get undefined.
Thanks
答案1
得分: 4
以下是使用.reduce()
的快速解决方案:
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} ];
const result = input.reduce((acc, obj) => {
if(!acc[obj.year]) acc[obj.year] = {};
if(!acc[obj.year][obj.month]) acc[obj.year][obj.month] = [];
acc[obj.year][obj.month].push(obj);
return acc;
}, {});
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 -->
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} ];
const result = input.reduce((acc, obj) => {
if(!acc[obj.year]) acc[obj.year] = {};
if(!acc[obj.year][obj.month]) acc[obj.year][obj.month] = [];
acc[obj.year][obj.month].push(obj);
return acc;
}, {});
console.log('result:', result);
<!-- end snippet -->
Docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论