Javascript 如何使用 Lodash 基于一个键合并两个集合?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35091975/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use Lodash to merge two collections based on a key?
提问by murvinlai
I have two collections, and the objects have a common key "userId". As below:
我有两个集合,对象有一个公共键“userId”。如下:
var _= require('lodash');
var a = [
{ userId:"p1", item:1},
{ userId:"p2", item:2},
{ userId:"p3", item:4}
];
var b = [
{ userId:"p1", profile:1},
{ userId:"p2", profile:2}
];
I want to merge them based on "userId" to produce:
我想根据“userId”合并它们以产生:
[ { userId: 'p1', item: 1, profile: 1 },
{ userId: 'p2', item: 2, profile:2 },
{ userId: 'p3', item: 4 } ]
I have these so far:
到目前为止,我有这些:
var u = _.uniq(_.union(a, b), false, _.property('userId'));
Which result in:
结果是:
[ { userId: 'p1', item: 1 },
{ userId: 'p2', item: 2 },
{ userId: 'p3', item: 4 },
{ userId: 'p1', profile: 1 },
{ userId: 'p2', profile: 2 } ]
How can I merge them now?
我现在如何合并它们?
I tried _.keyBy but it results in:
我试过 _.keyBy 但结果是:
{ p1: { userId: 'p1', profile: 1 },
p2: { userId: 'p2', profile: 2 },
p3: { userId: 'p3', item: 4 } }
which is wrong.
这是错误的。
What's the last step I should do?
我应该做的最后一步是什么?
回答by Tushar
You can use _.map()
, _.assign()
and _.find()
.
您可以使用_.map()
,_.assign()
和_.find()
。
// Iterate over first array of objects
_.map(a, function(obj) {
// add the properties from second array matching the userID
// to the object from first array and return the updated object
return _.assign(obj, _.find(b, {userId: obj.userId}));
});
var a = [{
userId: "p1",
item: 1
}, {
userId: "p2",
item: 2
}, {
userId: "p3",
item: 4
}];
var b = [{
userId: "p1",
profile: 1
}, {
userId: "p2",
profile: 2
}];
var arrResult = _.map(a, function(obj) {
return _.assign(obj, _.find(b, {
userId: obj.userId
}));
});
console.log(arrResult);
document.getElementById('result').innerHTML = JSON.stringify(arrResult, 0, 4);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.1.0/lodash.min.js"></script>
<pre id="result"></pre>
回答by Jorjon
Highest voted answer doesn't do proper merge. If second array contains an unique property, it is not taken into account.
得票最高的答案没有进行适当的合并。如果第二个数组包含唯一属性,则不考虑。
This approach does a proper merge.
这种方法进行了适当的合并。
Lodash
洛达什
var a = [
{ userId:"p1", item:1},
{ userId:"p2", item:2},
{ userId:"p3", item:4}
];
var b = [
{ userId:"p1", profile:1},
{ userId:"p2", profile:2},
{ userId:"p4", profile:4}
];
var merged = _.merge(_.keyBy(a, 'userId'), _.keyBy(b, 'userId'));
var values = _.values(merged);
console.log(values);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
ES6+
ES6+
// from https://stackoverflow.com/a/34749873/80766
const mergeDeep = (target, ...sources) => {
if (!sources.length) return target;
const source = sources.shift();
if (target instanceof Object && source instanceof Object) {
for (const key in source) {
if (source[key] instanceof Object) {
if (!target[key]) Object.assign(target, { [key]: {} });
mergeDeep(target[key], source[key]);
} else {
Object.assign(target, { [key]: source[key] });
}
}
}
return mergeDeep(target, ...sources);
}
const a = [
{ userId:"p1", item:1},
{ userId:"p2", item:2},
{ userId:"p3", item:4}
];
const b = [
{ userId:"p1", profile:1},
{ userId:"p2", profile:2},
{ userId:"p4", profile:4}
];
const aKeyed = a.reduce((acc, cur) => ({ ...acc, [cur.userId]: cur }), {});
const bKeyed = b.reduce((acc, cur) => ({ ...acc, [cur.userId]: cur }), {});
const merged = mergeDeep(aKeyed, bKeyed);
const values = Object.values(merged);
console.log(values);
回答by Nina Scholz
Just for completeness: A proposal without any library.
只是为了完整性:一个没有任何图书馆的提案。
function merge(a, b, key) {
function x(a) {
a.forEach(function (b) {
if (!(b[key] in obj)) {
obj[b[key]] = obj[b[key]] || {};
array.push(obj[b[key]]);
}
Object.keys(b).forEach(function (k) {
obj[b[key]][k] = b[k];
});
});
}
var array = [],
obj = {};
x(a);
x(b);
return array;
}
var a = [
{ userId: "p1", item: 1 },
{ userId: "p2", item: 2 },
{ userId: "p3", item: 4 }
],
b = [
{ userId: "p1", profile: 1 },
{ userId: "p2", profile: 2 }
],
c = merge(a, b, 'userId');
document.write('<pre>' + JSON.stringify(c, 0, 4) + '</pre>');
回答by Nicolas Le Thierry d'Ennequin
Lodash has a merge
method that works on objects (objects with the same key are merged). In this demo, the arrays a
and b
are first converted into objects (where userId
is the key), then merged, and the result converted back to an array (_.values
) (getting rid of the keys). _.flatten
is then necessary because _.values
adds an extra level of array.
Lodash 有一个merge
处理对象的方法(合并具有相同键的对象)。在这个演示中,数组a
和b
首先被转换为对象(其中userId
是键),然后合并,结果转换回数组(_.values
)(去掉键)。_.flatten
然后是必要的,因为_.values
添加了额外的数组级别。
var u= _({}) // Start with an empty object
.merge(
_(a).groupBy("userId").value(),
_(b).groupBy("userId").value()
)
.values()
.flatten()
.value();
回答by garrettmac
ES6+ version without lodash.
没有 lodash 的 ES6+ 版本。
const array1 = [{ userId: "p1", item: 1 }, { userId: "p2", item: 2 },{ userId: "p3", item: 4 }];
const array2 = [{ userId: "p1", profile: 1 }, { userId: "p2", profile: 2 }];
const result = array1.map(a => ({
...a,
...array2.find(b => b.userId === a.userId) // _.find(array2, 'skuId') <-- or with lodash
}));
document.write('<pre>' + JSON.stringify(result, 0, 2) + '</pre>');
回答by ofir fridman
Try this demo
试试这个演示
var a = [{
userId: "p1",
item: 1
}, {
userId: "p2",
item: 2
}, {
userId: "p3",
item: 4
}];
var b = [{
userId: "p1",
profile: 1
}, {
userId: "p2",
profile: 2
}];
a.forEach(function (aitem) {
b.forEach(function (bitem) {
if(aitem.userId === bitem.userId) {
_.assign(aitem, bitem);
}
});
});
console.log(a);