我有两个对象数组,如下所示:
array1 = [
{ material: "ABC123", cost: 100 },
{ material: "DEF456", cost: 150 }
]
array2 = [
{ material: "ABC123", date: "1/1/20", quantity: 4 },
{ material: "ABC123", date: "1/15/20", quantity: 1 },
{ material: "ABC123", date: "2/15/20", quantity: 3 },
{ material: "ABC123", date: "4/15/21", quantity: 1 },
{ material: "DEF456", date: "3/05/20", quantity: 6 },
{ material: "DEF456", date: "3/18/20", quantity: 1 },
{ material: "DEF456", date: "5/15/21", quantity: 2 }
]
我想创建一个新的对象数组,其中包含来自 array1 的所有键/值对以及每个项目按年份和月份的汇总数量。
结果是:
[
ABC123: {
cost: 100,
byYear: {
2020: {
byMonth: {
1: 5,
2: 3
}
}
},
{
2021: {
byMonth: {
4: 1
}
}
},
},
DEF456: {
cost: 150,
byYear: {
2020: {
byMonth: {
3: 7,
2: 3
}
}
},
{
2021: {
byMonth: {
5: 2
}
}
},
}
]
以下是迄今为止我的代码,使用 lodash,但这在解决方案中不是必需的。我遇到的问题是,在每个项目下创建的年份和月份键并非特定于该项目。每个项目都获得所有项目存在的年和月键。
let itemSummary = {};
_.forEach(array1, function (item) {
itemSummary[item["material"]] = itemSummary[item["material"]] || {}; // create material as key
itemSummary[item["material"]] = item; // add props from array1 under each key
_.forEach(array2, function (trans) {
// iterate through transactions and aggregate by year and month
let transactionYear = new Date(trans["date"]).getFullYear();
let transactionMonth = new Date(trans["date"]).getMonth() + 1;
itemSummary[item["material"]]["byYear"] = itemSummary[item["material"]]["byYear"] || {}; //create year key
itemSummary[item["material"]]["byYear"][transactionYear] = itemSummary[item["material"]]["byYear"][transactionYear] || {}; // set year key
itemSummary[item["material"]]["byYear"][transactionYear]["byMonth"] = itemSummary[item["material"]]["byYear"][transactionYear]["byMonth"] || {};
itemSummary[item["material"]]["byYear"][transactionYear]["byMonth"][transactionMonth] =
itemSummary[item["material"]]["byYear"][transactionYear]["byMonth"][transactionMonth] || {};
});
});
显然,这并没有像我上面提到的那样汇总数量,因为我首先需要为每个项目获取正确的年份和月份键。
非常感谢任何帮助
答案 0 :(得分:2)
您可以对所有分组和另一个对象采用动态方法来获得最终总和。
const
array1 = [{ material: "ABC123", cost: 100 }, { material: "DEF456", cost: 150 }],
array2 = [{ material: "ABC123", date: "1/1/20", quantity: 4 }, { material: "ABC123", date: "1/15/20", quantity: 1 }, { material: "ABC123", date: "2/15/20", quantity: 3 }, { material: "ABC123", date: "4/15/21", quantity: 1 }, { material: "DEF456", date: "3/05/20", quantity: 6 }, { material: "DEF456", date: "3/18/20", quantity: 1 }, { material: "DEF456", date: "5/15/21", quantity: 2 }],
groups = [
({ material }) => material,
_ => 'byYear',
({ date }) => '20' + date.split('/')[2],
_ => 'byMonth'
],
sum = {
key: ({ date }) => date.split('/')[0],
value: ({ quantity }) => quantity
},
result = array2.reduce(
(r, o) => {
const temp = groups.reduce((t, fn) => t[fn(o)] ??= {}, r);
temp[sum.key(o)] ??= 0;
temp[sum.key(o)] += sum.value(o);
return r;
},
Object.fromEntries(array1.map(({ material, cost }) => [material, { cost }]))
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
如有必要,您可以添加进一步的分组并添加一个函数数组以进行最终聚合。
const
array1 = [{ material: "ABC123", cost: 100 }, { material: "DEF456", cost: 150 }],
array2 = [{ material: "ABC123", date: "1/1/20", quantity: 4 }, { material: "ABC123", date: "1/15/20", quantity: 1 }, { material: "ABC123", date: "2/15/20", quantity: 3 }, { material: "ABC123", date: "4/15/21", quantity: 1 }, { material: "DEF456", date: "3/05/20", quantity: 6 }, { material: "DEF456", date: "3/18/20", quantity: 1 }, { material: "DEF456", date: "5/15/21", quantity: 2 }],
groups = [
({ material }) => material,
_ => 'byYear',
({ date }) => '20' + date.split('/')[2],
_ => 'byMonth',
({ date }) => date.split('/')[0]
],
ultimately = [
(target, { quantity }) => {
target.sum ??= 0;
target.sum += quantity;
},
(target, { quantity }) => {
target.max ??= quantity;
if (quantity > target.max) target.max = quantity;
}
],
result = array2.reduce(
(r, o) => {
const temp = groups.reduce((t, fn) => t[fn(o)] ??= {}, r);
ultimately.forEach(fn => fn(temp, o));
return r;
},
Object.fromEntries(array1.map(({ material, cost }) => [material, { cost }]))
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 1 :(得分:1)
可能有多种方法可以达到您想要的格式,这里是其中之一。我选择以 array1 为基础,因为它看起来像主列表,但你也可以以 array2 为基础。
我们从 array1 中取出每一项,从 array2 中过滤匹配的材料,然后通过 reduce 运行它们,在那里我们解析日期并构建对象来存储 byYear 和 byMonth
array1 = [
{ material: "ABC123", cost: 100 },
{ material: "DEF456", cost: 150 }
]
array2 = [
{ material: "ABC123", date: "1/1/20", quantity: 4 },
{ material: "ABC123", date: "1/15/20", quantity: 1 },
{ material: "ABC123", date: "2/15/20", quantity: 3 },
{ material: "ABC123", date: "4/15/21", quantity: 1 },
{ material: "DEF456", date: "3/05/20", quantity: 6 },
{ material: "DEF456", date: "3/18/20", quantity: 1 },
{ material: "DEF456", date: "5/15/21", quantity: 2 }
]
let data = array1.reduce((b, a) => {
let thing = a.hasOwnProperty('material') ? 'material' : 'part';
let items = array2.filter(e => e.material === a[thing]).reduce((d, c) => {
let dt = c.date.split("/"),
m = dt[0],
y = new Date(dt).getFullYear()
if (d.hasOwnProperty(y)) {
if (d[y].byMonth.hasOwnProperty(m)) d[y].byMonth[m]+= +c.quantity;
else d[y].byMonth[m] = c.quantity;
} else d[y] = {byMonth: {[m]: c.quantity}};
return d
}, {}) ;
b[a[thing]] = {
cost: a.cost,
byYear: items
};
return b
}, {})
console.log(data)