在 JavaScript 中,有一种优雅的方法可以合并两个对象并对所有共同属性求和吗?
In JavaScript there an elegant way to merge two Objects and sum any common properties?
我正在对大量对象进行重复数据删除,其中许多对象具有一些共同的属性。所有属性都是整数。
遍历键并手动合并非常容易,但我忍不住觉得 Object.assign
和 map
以及 reduce
的某种组合可以做到这是一条线。随着语言的成熟,似乎值得保持领先地位。
编辑:举个例子:
let A = {
"a": 10,
"e": 2,
"g": 14
}
let B = {
"b": 3,
"e": 15,
"f": 1,
"g": 2,
"h": 11
}
let C = Object.magicMerge(A, B)
/*
{
"a": 10,
"e": 17,
"g": 16
"b": 3,
"f": 1,
"h": 11
}
*/
vanilla JS 中实际上没有任何捷径,您必须显式地遍历每个对象和每个 属性,并以某种方式将它们相加。一种选择是使用 reduce
:
进行分组
const arr = [{
foo: 1,
bar: 2
}, {
bar: 5,
baz: 7
}, {
baz: 10,
buzz: 10
}];
const combined = arr.reduce((a, obj) =>
Object.entries(obj).reduce((a, [key, val]) => {
a[key] = (a[key] || 0) + val;
return a;
}, a)
, {});
console.log(combined);
我更喜欢 reduce
,因为外部 combined
变量一旦创建,就不会在其范围内发生变化,但如果您愿意,可以使用 for..of
代替:
const arr = [{
foo: 1,
bar: 2
}, {
bar: 5,
baz: 7
}, {
baz: 10,
buzz: 10
}];
const combined = {};
for (const obj of arr) {
for (const [key, val] of Object.entries(obj)) {
combined[key] = (combined[key] || 0) + val;
}
}
console.log(combined);
是的,在我看来您需要合并键然后合并对象。尝试了一个更简单的解决方案,但这个(虽然比我喜欢的时间更长)可以完成工作,并且适用于任意数量的对象。
const object1 = {
a: 4,
c: 2.2,
d: 43,
g: -18
}, object2 = {
b: -22.4,
c: 14,
d: -42,
f: 13.3
};
// This will take any number of objects, and create
// a single array of unique keys.
const mergeKeys = (objects)=>{
let keysArr = objects.reduce((acc, object)=>{
acc.push(...Object.keys(object));
acc = [...new Set(acc.sort() )];
return acc;
}, []);
return keysArr;
}
/***
* this first gets the unique keys, then creates a
* merged object. Each object is checked for each
* property, and if it exists, we combine them.
* if not, we simply keep the current value.
*
***/
const combineAnyNumberOfObjects = (...objects)=>{
const keys = mergeKeys(objects),
returnObj = {};
keys.forEach(key=>{
returnObj[key]=0;
objects.forEach(object=>{
returnObj[key] = !!object[key] ? returnObj[key]+object[key] : returnObj[key]
})
})
return returnObj;
}
console.log(combineAnyNumberOfObjects(object1, object2));
如您所说,合并和手动添加每个道具都非常容易。上面的一行答案?美丽的。 ;)
我愿意:
function objTotals(array){
const r = {};
array.forEach(o => {
for(let i in o){
if(!(i in r))r[i] = 0;
}
});
for(let i in r){
array.forEach(o => {
if(i in o)r[i]+=o[i];
});
}
return r;
}
const a = [{a:0, b:2, c:5, d:1, e:2}, {a:1, b:3}, {a:5, b:7, c:4}, {a:2, b:1, c:9, d:11}];
console.log(objTotals(a));
我会这样做:
const a = { "a": 10, "e": 2, "g": 14 };
const b = { "b": 3, "e": 15, "f": 1, "g": 2, "h": 11 };
const sum = [...Object.entries(a), ...Object.entries(b)]
.reduce(
(acc, [key, val]) => ({ ...acc, [key]: (acc[key] || 0) + val }),
{}
);
console.log("sum:", sum);
你问的一个班轮:)
在我看来,这是最优雅的方式。
这里有一些没有 loops/reduce:
let C = Object.fromEntries(
Object.keys(A)
.concat(Object.keys(B))
.map(k => [k,
(A[k] || 0) + (B[k] || 0)
])
)
这是一个适用于任意数量对象的通用函数:
let mergeSum = (...objs) => Object.fromEntries(
Array.from(
new Set(objs.flatMap(Object.keys)),
k => [k,
objs
.map(o => o[k] || 0)
.reduce((a, b) => a + b)
]))
C = mergeSum(A, B)
或更通用:
let mergeReduce = (objs, fn, init) => Object.fromEntries(
Array.from(
new Set(objs.flatMap(Object.keys)),
k => [k, objs.map(o => o[k]).reduce(fn, init)]
));
// for example:
sumOfProps = mergeReduce([A, B],
(a, b) => (a || 0) + (b || 0))
listOfProps = mergeReduce([A, B],
(a, b) => b ? a.concat(b) : a,
[])
我正在对大量对象进行重复数据删除,其中许多对象具有一些共同的属性。所有属性都是整数。
遍历键并手动合并非常容易,但我忍不住觉得 Object.assign
和 map
以及 reduce
的某种组合可以做到这是一条线。随着语言的成熟,似乎值得保持领先地位。
编辑:举个例子:
let A = {
"a": 10,
"e": 2,
"g": 14
}
let B = {
"b": 3,
"e": 15,
"f": 1,
"g": 2,
"h": 11
}
let C = Object.magicMerge(A, B)
/*
{
"a": 10,
"e": 17,
"g": 16
"b": 3,
"f": 1,
"h": 11
}
*/
vanilla JS 中实际上没有任何捷径,您必须显式地遍历每个对象和每个 属性,并以某种方式将它们相加。一种选择是使用 reduce
:
const arr = [{
foo: 1,
bar: 2
}, {
bar: 5,
baz: 7
}, {
baz: 10,
buzz: 10
}];
const combined = arr.reduce((a, obj) =>
Object.entries(obj).reduce((a, [key, val]) => {
a[key] = (a[key] || 0) + val;
return a;
}, a)
, {});
console.log(combined);
我更喜欢 reduce
,因为外部 combined
变量一旦创建,就不会在其范围内发生变化,但如果您愿意,可以使用 for..of
代替:
const arr = [{
foo: 1,
bar: 2
}, {
bar: 5,
baz: 7
}, {
baz: 10,
buzz: 10
}];
const combined = {};
for (const obj of arr) {
for (const [key, val] of Object.entries(obj)) {
combined[key] = (combined[key] || 0) + val;
}
}
console.log(combined);
是的,在我看来您需要合并键然后合并对象。尝试了一个更简单的解决方案,但这个(虽然比我喜欢的时间更长)可以完成工作,并且适用于任意数量的对象。
const object1 = {
a: 4,
c: 2.2,
d: 43,
g: -18
}, object2 = {
b: -22.4,
c: 14,
d: -42,
f: 13.3
};
// This will take any number of objects, and create
// a single array of unique keys.
const mergeKeys = (objects)=>{
let keysArr = objects.reduce((acc, object)=>{
acc.push(...Object.keys(object));
acc = [...new Set(acc.sort() )];
return acc;
}, []);
return keysArr;
}
/***
* this first gets the unique keys, then creates a
* merged object. Each object is checked for each
* property, and if it exists, we combine them.
* if not, we simply keep the current value.
*
***/
const combineAnyNumberOfObjects = (...objects)=>{
const keys = mergeKeys(objects),
returnObj = {};
keys.forEach(key=>{
returnObj[key]=0;
objects.forEach(object=>{
returnObj[key] = !!object[key] ? returnObj[key]+object[key] : returnObj[key]
})
})
return returnObj;
}
console.log(combineAnyNumberOfObjects(object1, object2));
如您所说,合并和手动添加每个道具都非常容易。上面的一行答案?美丽的。 ;)
我愿意:
function objTotals(array){
const r = {};
array.forEach(o => {
for(let i in o){
if(!(i in r))r[i] = 0;
}
});
for(let i in r){
array.forEach(o => {
if(i in o)r[i]+=o[i];
});
}
return r;
}
const a = [{a:0, b:2, c:5, d:1, e:2}, {a:1, b:3}, {a:5, b:7, c:4}, {a:2, b:1, c:9, d:11}];
console.log(objTotals(a));
我会这样做:
const a = { "a": 10, "e": 2, "g": 14 };
const b = { "b": 3, "e": 15, "f": 1, "g": 2, "h": 11 };
const sum = [...Object.entries(a), ...Object.entries(b)]
.reduce(
(acc, [key, val]) => ({ ...acc, [key]: (acc[key] || 0) + val }),
{}
);
console.log("sum:", sum);
这里有一些没有 loops/reduce:
let C = Object.fromEntries(
Object.keys(A)
.concat(Object.keys(B))
.map(k => [k,
(A[k] || 0) + (B[k] || 0)
])
)
这是一个适用于任意数量对象的通用函数:
let mergeSum = (...objs) => Object.fromEntries(
Array.from(
new Set(objs.flatMap(Object.keys)),
k => [k,
objs
.map(o => o[k] || 0)
.reduce((a, b) => a + b)
]))
C = mergeSum(A, B)
或更通用:
let mergeReduce = (objs, fn, init) => Object.fromEntries(
Array.from(
new Set(objs.flatMap(Object.keys)),
k => [k, objs.map(o => o[k]).reduce(fn, init)]
));
// for example:
sumOfProps = mergeReduce([A, B],
(a, b) => (a || 0) + (b || 0))
listOfProps = mergeReduce([A, B],
(a, b) => b ? a.concat(b) : a,
[])