我需要迭代三个对象,以检查重复项是否以单个对象结束。如果有重复项,我想将它们放入数组中,以便用户可以选择最佳值,这样它们最终最终都将成为字符串或整数(或带有字符串/整数的对象)。他们可能看起来像这样:
const a = {
first_name: 'Tom',
height: {
feet: 5,
inches: 0
}
}
const b = {
first_name: 'Thomas',
last_name: 'Walsh',
email: 'tomwalsh@domain.com',
height: {
feet: 6,
inches: 0
}
}
const c = {
email: 'tomwalsh@sample.edu'
}
结果如下:
const result = {
first_name: ['Tom', 'Thomas'],
last_name: 'Walsh',
email: ['tomwalsh@domain.com', 'tomwalsh@sample.edu'],
height: {
feet: [5, 6],
inches: 0
}
}
我不知道a
,b
或c
是否是键的权威,所以我不得不假设一组未知的键/值对,但是绝对很小(不超过20对,只有2-3个深度超过3个级别,每个级别最多可以有4-5个键/值对。
我可以创建一个新对象,递归地迭代三个对象,然后转储值或创建值数组,但这似乎效率很低。有什么建议吗?
如果需要,我在项目中有lodash。谢谢!
答案 0 :(得分:1)
由于某些对象中可能缺少嵌套键,因此您可以通过lodash的_.mergeWith()
合并它们,并将重复项收集到数组中:
const a = {"first_name":"Tom","height":{"feet":5,"inches":0}}
const b = {"first_name":"Thomas","last_name":"Walsh","email":"tomwalsh@domain.com","height":{"feet":6,"inches":0}}
const c = {"email":"tomwalsh@sample.edu"}
const shouldCollect = (s) => _.negate(_.overSome([
_.isUndefined,
_.isObject,
_.partial(_.eq, s)
]))
const mergeDupes = (...args) => _.mergeWith({}, ...args, (o, s) => {
if(_.isArray(o)) return _.uniq([...o, s]);
if(shouldCollect(s)(o)) return [o, s];
})
const result = mergeDupes(a, b, c)
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
如果要删除非重复属性,则可以通过递归_.transform()
来清理对象:
const a = {"first_name":"Tom","height":{"feet":5,"inches":0}}
const b = {"first_name":"Thomas","last_name":"Walsh","email":"tomwalsh@domain.com","height":{"feet":6,"inches":0}}
const c = {"email":"tomwalsh@sample.edu"}
const shouldCollect = (s) => _.negate(_.overSome([
_.isUndefined,
_.isObject,
_.partial(_.eq, s)
]))
const omitNonDuplicates = obj =>
_.transform(obj, (a, v, k) => {
if (_.isArray(v)) a[k] = v;
else if (_.isObject(v)) {
const clean = omitNonDuplicates(v);
if(!_.isEmpty(clean)) a[k] = clean;
return;
}
});
const mergeDupes = (...args) => omitNonDuplicates(_.mergeWith({}, ...args, (o, s) => {
if(_.isArray(o)) return _.uniq([...o, s]);
if(shouldCollect(s)(o)) return [o, s];
}))
const result = mergeDupes(a, b, c)
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
答案 1 :(得分:0)
我认为没有功能可以执行此操作,您必须迭代它们的属性。
const a = { first_name: 'Tom', height: {feet: 5, inches: 0 } };
const b = { first_name: 'Thomas', last_name: 'Walsh', email:'tomwalsh@domain.com', height: { feet: 6, inches: 0} };
const c = { email: 'tomwalsh@sample.edu' };
let newObj = {};
[a, b, c].forEach(obj => {
Object.entries(obj).forEach(([key, value]) => {
if (newObj.hasOwnProperty(key)) { // if the property exist
if (Array.isArray(newObj[key])) {
newObj[key].push(value);
} else {
let temporalVal = newObj[key];
newObj[key] = [temporalVal, value];
}
} else { // if the property does not exist, create it.
newObj[key] = value;
}
})
});
console.log(newObj)
答案 2 :(得分:0)
您将需要一个递归函数,该函数将一并进入对象属性:
function mergeObjects(objs) {
objs = objs.filter(obj => obj !== undefined);
// return value or array when at least one of the values is a primitive
if (objs.some(obj => Object(obj) !== obj)) {
objs = Array.from(new Set(objs)); // Get unique values
return objs.length === 1 ? objs[0] : objs;
}
// Get all the keys
const keys = Array.from(new Set([].concat(...objs.map(obj => Object.keys(obj)))));
return Object.assign({}, ...keys.map(key =>
({ [key]: mergeObjects(objs.map(obj => obj[key])) })));
}
// Demo:
const a = {first_name: 'Tom', height: {feet: 5,inches: 0}};
const b = {first_name: 'Thomas',last_name: 'Walsh',email: 'tomwalsh@domain.com', height: {feet: 6,inches: 0}};
const c = {email: 'tomwalsh@sample.edu'};
const result = mergeObjects([a,b, c]);
console.log(result);
答案 3 :(得分:0)
您可以通过检查值来采用递归方法,并在嵌套对象中获取内部值。
const
merge = (a, b) => {
Object.entries(b).forEach(([k, v]) => {
if (v && typeof v === 'object') {
return merge(a[k] = a[k] || {}, v);
}
if (!(k in a)) {
return a[k] = v;
}
if ([].concat(a[k]).includes(v)) {
return;
}
a[k] = [].concat(a[k], v);
});
return a;
},
a = { first_name: 'Tom', height: { feet: 5, inches: 0 } },
b = { first_name: 'Thomas', last_name: 'Walsh', email: 'tomwalsh@domain.com', height: { feet: 6, inches: 0 } },
c = { email: 'tomwalsh@sample.edu', height: { feet: 15 } },
result = [a, b, c].reduce(merge, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 4 :(得分:0)
这是通过Array.reduce
和Array.forEach
的简洁递归解决方案:
const a = { first_name: 'Tom', height: { feet: 5, inches: 0 } },
b = { first_name: 'Thomas', last_name: 'Walsh', email: 'tomwalsh@domain.com', height: { feet: 6, inches: 0 } },
c = { email: 'tomwalsh@sample.edu'},
d = { first_name: 'Tomy', height: { feet: 15, inches: 10 } }
const mergeKeys = (a,b) => {
if(a != undefined) {
if(a === b) return a
if(typeof b == 'object') return merge([a,b])
else return [...(Array.isArray(a) ? a : [a]), b]
} else return b
}
const merge = arr => arr.reduce((r,c) =>
(Object.entries(c).forEach(([k,v]) => r[k] = mergeKeys(r[k],c[k])), r) ,{})
console.log(merge([a,b,c,d]))
答案 5 :(得分:0)