如何通过减去属性(深度水平如何)获得两个对象的差异?
我想减去完全相同结构的两个对象的值。尽管存在一个答案在这里,它仅限于无数据的对象。就我而言,我正在寻找一个可靠的解决方案,只要它们具有相同的结构,就可以减去任何深度的对象。
示例
考虑以下两个对象, EarthData2022
和 earthdata2050
:
const earthData2022 = {
distanceFromSun: 149280000,
continents: {
asia: {
area: 44579000,
population: 4560667108,
countries: { japan: { temperature: 62.5 } },
},
africa: { area: 30370000, population: 1275920972 },
europe: { area: 10180000, population: 746419440 },
america: { area: 42549000, population: 964920000 },
australia: { area: 7690000, population: 25925600 },
antarctica: { area: 14200000, population: 5000 },
},
};
const earthData2050 = {
distanceFromSun: 149280000,
continents: {
asia: {
area: 44579000,
population: 4560767108,
countries: { japan: { temperature: 73.6 } },
},
africa: { area: 30370000, population: 1275960972 },
europe: { area: 10180000, population: 746419540 },
america: { area: 42549000, population: 964910000 },
australia: { area: 7690000, population: 25928600 },
antarctica: { area: 14200000, population: 5013 },
},
};
请注意,这两个对象都有:
- 完全相同的结构
- 所有 values 是数字,是整数或整数小数。没有字符串或布尔值,也没有数组。
我想减去: seraindata2050
- erasedata2022
获得一个新对象:
// desired output
// continents' areas aren't expected to change so their diff is `0`
// likewise, the distance of earth from sun
const earthDataDiff = {
distanceFromSun: 0,
continents: {
asia: {
area: 0,
population: 100000,
countries: { japan: { temperature: 11.1 } },
},
africa: { area: 0, population: 40000 },
europe: { area: 0, population: 100 },
america: { area: 0, population: -10000 },
australia: { area: 0, population: 3000 },
antarctica: { area: 0, population: 13 },
},
};
如上所述,使用给定的甜蜜答案
function mySub(x, y) {
return Object.keys(x).reduce((a, k) => {
a[k] = x[k] - y[k];
return a;
}, {});
}
但是,当调用 mysub()
时,我们会得到此不太奇怪的输出:
mySub(earthData2050, earthData2022)
// {"distanceFromSun":0,"continents":null}
我的问题,因此,我是如何如果对象具有相同的结构,我可以递归减去所有条目, 有多深。另外,当我在节点上运行此代码时,我很乐意利用任何可能派上用场的新ecmascript功能。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
递归是你的朋友
recursion is your friend here
声明/功能解决方案:
解释
object.entries
将对象转换为二维键值对的数组。使用array.dray.duce
在对上迭代,它可以将数组减少到对象。一个类似的方法是,当您在烹饪时将肉汤减少到酱汁中时。如果该属性的值是对象,则结果属性应为子对象的差异(递归)的差异。如果不是,则必须是一个数字,因此可以减去。进一步阅读:
Declarative/functional solution:
Explaination
Object.entries
converts the object to a two-dimensional array of key value pairs. Usingarray.reduce
to iterate over the pairs, it can reduce the array to an object. An analogy of this would be when you're reducing a broth to a sauce while cooking. If the value of the property is an object, the resulting property should be the difference of the difference of the sub-object (recursion). If not, it has to be a number and can therefore be subtracted.Further reading:
@Scott的答案非常有效和优雅。他在帖子中评论 -
我想分享它的外观。在这里,我们将
objdiff
作为zipmap
的专业化 -其中
is
和zipmap
定义为 -取决于<<<。代码> unique -
为了进行演示,我在每个对象中添加了
samplearray
属性,hello:“ world”
键对。将下面的代码运行到objdiff
现在用于非对称输入和混合值类型 -@Scott's answer is remarkably efficient and elegant. In his post he comments -
I wanted to share what that would look like. Here we write
objDiff
as a specialization ofzipMap
-Where
is
andzipMap
is defined as -Which depends on
unique
-To demo this, I added a
sampleArray
property to each object and ahello: "world"
key pair to one. Run the code below toobjDiff
now works on asymmetric inputs and mixed values types -这是一种非常简单的递归方法:
我们将第一个对象中的条目映射到具有相同键的新条目和一个值,这是递归调用或减法的结果,是基于第一个值是对象还是数字。然后,我们使用
对象.fromentries
重建新对象。这仅在您的音符正确的情况下起作用,这两个对象具有相同的结构,并且叶子节点都是数字。如果我们想处理其他情况,我们将必须变得更加复杂。
Here's a pretty simple recursive approach:
We take the entries in your first object and map them to new entries with the same key and a value which is either the result of a recursive call or the subtraction, based on whether the first value is an object or a number. Then we use
Object .fromEntries
to rebuild a new object.This only works if your note is correct, that the two objects have identical structures and that leaf nodes are all numbers. We'd have to get more sophisticated if we wanted to handle other cases.