I would like to merge these two array of objects but for urls
I would like to use unshift to merge arrays instead of replacing.
Here's an example
var arr1 = [{
"keyword": "name",
"score": 0.8992112752974006,
"urls": ["url1"],
"ids": ["5748bf9ab58adb2f614da195"]
}, {
"keyword": "name1",
"score": 0.39953909596222775,
"urls": ["url2"],
"ids": ["5743260055f979a31fa98971"]
}, {
"keyword": "name3",
"score": 0.4960953181766197,
"urls": ["url4"],
"ids": ["58c04cd5208b4945c3920cad"]
}, {
"keyword": "name4",
"score": 0.3337163443410707,
"urls": ["url5"],
"ids": ["573628c38e32eeb039377f7e"]
}];
var arr2 = [{
"keyword": "name",
"score": 0.8992112752974006,
"urls": ["url6"],
"ids": [""]
}, {
"keyword": "name1",
"score": 0.39953909596222775,
"urls": ["url7"],
"ids": [""]
}]
I would like the result to be
[{
"keyword": "name",
"score": 0.8992112752974006,
"urls": ["url6", "url1"],
"ids": ["5748bf9ab58adb2f614da195"]
}, {
"keyword": "name1",
"score": 0.39953909596222775,
"urls": ["url7", "url2"],
"ids": ["5743260055f979a31fa98971"]
}, {
"keyword": "name3",
"score": 0.4960953181766197,
"urls": ["url4"],
"ids": ["58c04cd5208b4945c3920cad"]
}, {
"keyword": "name4",
"score": 0.3337163443410707,
"urls": ["url5"],
"ids": ["573628c38e32eeb039377f7e"]
}];
Here's my attempt but the result would replace the array of urls;
var a3 = arr1.concat(arr2).reduce((acc, x) => {
acc[x.keyword] = Object.assign(acc[x.keyword] || {}, x);
return acc;
}, {});
console.log(a3);
It would be just the urls
that it will be merged. Other values will be overridden.
You could use a Map
for collecting the objects with the same keyword
and update if necessary. This solution works for an arbitrary count of arrays.
var array1 = [{ keyword: "name", score: 0.8992112752974006, urls: ["url1"], ids: ["5748bf9ab58adb2f614da195"] }, { keyword: "name1", score: 0.39953909596222775, urls: ["url2"], ids: ["5743260055f979a31fa98971"] }, { keyword: "name3", score: 0.4960953181766197, urls: ["url4"], ids: ["58c04cd5208b4945c3920cad"] }, { keyword: "name4", score: 0.3337163443410707, urls: ["url5"], ids: ["573628c38e32eeb039377f7e"] }], array2 = [{ keyword: "name", score: 0.8992112752974006, urls: ["url6"], ids: [""] }, { keyword: "name1", score: 0.39953909596222775, urls: ["url7"], ids: [""] }], map = new Map, result = [], fn = a => { if (map.has(a.keyword)) { map.get(a.keyword).urls.unshift(...a.urls); return; } map.set(a.keyword, a); result.push(a); }; [array1, array2].forEach(a => a.forEach(fn)); console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I prefer doing this with a Map instead of reduce:
const result = [], hash = new Map();
arr1.concat(arr2).forEach( obj => {
if( hash.has( obj.keyword ) ){
hash.get( obj.keyword ).urls.push(...obj.urls);
}else{
hash.set( obj.keyword, obj);
result.push( obj );
}
});
You can take the urls
property out of the object before you assign to a new object, then add it back if it doesn't exist, or unshift
into the existing array, if it does exist
var arr1 = [{ "keyword": "name", "score": 0.8992112752974006, "urls": ["url1"], "ids": ["5748bf9ab58adb2f614da195"] }, { "keyword": "name1", "score": 0.39953909596222775, "urls": ["url2"], "ids": ["5743260055f979a31fa98971"] }, { "keyword": "name3", "score": 0.4960953181766197, "urls": ["url4"], "ids": ["58c04cd5208b4945c3920cad"] }, { "keyword": "name4", "score": 0.3337163443410707, "urls": ["url5"], "ids": ["573628c38e32eeb039377f7e"] }]; var arr2 = [{ "keyword": "name", "score": 0.8992112752974006, "urls": ["url6"], "ids": [""] }, { "keyword": "name1", "score": 0.39953909596222775, "urls": ["url7"], "ids": [""] }] var a3 = arr1.concat(arr2).reduce((acc, x) => { let urls = x.urls; // store temporarily delete x.urls; // delete before merging, to not overwrite acc[x.keyword] = Object.assign(acc[x.keyword] || {}, x); 'urls' in acc[x.keyword] ? [].unshift.apply(acc[x.keyword].urls, urls) : acc[x.keyword].urls = urls; // ^ if exists unshift or just add return acc; }, {}); console.log(a3);
For no side effects on arr1
or arr2
you'll also need some kind of clone.
const a3 = ((a1, a2) => {
const copy = item => {
return {
keyword: item.keyword,
score: item.score,
urls: item.urls.slice(),
ids: item.ids.slice()
};
};
a1 = a1.map(copy);
const dictionary = a1.reduce((acc, item) => {
acc[item.keyword] = item;
return acc;
}, {});
a2.forEach(item => {
if (dictionary[item.keyword]) {
dictionary[item.keyword].urls = item.urls.concat(dictionary[item.keyword].urls);
} else {
const clone = copy(item);
dictionary[clone.keyword] = clone;
a1.push(clone);
}
});
return a1;
})(arr1, arr2);
I wrote this using arrows as function shorthand/ const
, but the rest is ES5
I used a spread operator to merge the arrays but unshift()
would work just as well.
function mergeObjects(arrayA, arrayB) { var // Take all items in arrayA and place them in the result. result = arrayA.slice(0); // Iterate over all items in array B arrayB.forEach(item => { var // Check if there is an item in the result with the same keyword. resultItem = result.find(itemA => itemA.keyword === item.keyword); // When the keyword isn't yet in the result... if (resultItem === null) { // ... add it to the result result.push(item); } else { // ... or else add the urls from the current item to the urls of the result. resultItem.urls = [...item.urls, ...resultItem.urls]; } }); // Return the result array. return result; } var arr1 = [{ "keyword": "name", "score": 0.8992112752974006, "urls": ["url1"], "ids": ["5748bf9ab58adb2f614da195"] }, { "keyword": "name1", "score": 0.39953909596222775, "urls": ["url2"], "ids": ["5743260055f979a31fa98971"] }, { "keyword": "name3", "score": 0.4960953181766197, "urls": ["url4"], "ids": ["58c04cd5208b4945c3920cad"] }, { "keyword": "name4", "score": 0.3337163443410707, "urls": ["url5"], "ids": ["573628c38e32eeb039377f7e"] }]; var arr2 = [{ "keyword": "name", "score": 0.8992112752974006, "urls": ["url6"], "ids": [""] }, { "keyword": "name1", "score": 0.39953909596222775, "urls": ["url7"], "ids": [""] }]; console.log(mergeObjects(arr1, arr2));
ES5 optimized approach ( without unnecessary iterations , just " low-level " processing):
var arr1 = [{ keyword: "name", score: 0.8992112752974006, urls: ["url1"], ids: ["5748bf9ab58adb2f614da195"] }, { keyword: "name1", score: 0.39953909596222775, urls: ["url2"], ids: ["5743260055f979a31fa98971"] }, { keyword: "name3", score: 0.4960953181766197, urls: ["url4"], ids: ["58c04cd5208b4945c3920cad"] }, { keyword: "name4", score: 0.3337163443410707, urls: ["url5"], ids: ["573628c38e32eeb039377f7e"] }], arr2 = [{ keyword: "name", score: 0.8992112752974006, urls: ["url6"], ids: [""] }, { keyword: "name1", score: 0.39953909596222775, urls: ["url7"], ids: [""] }], len1 = arr1.length, c = 0, k = -1; while (c < len1 && (l = arr2.length)) { for (i=0; i<l; i++) { if (arr1[c].keyword == arr2[i].keyword) { arr1[c].urls.unshift(arr2[i].urls[0]); k = i; break; } } if (k >=0) { arr2.splice(k, 1); k = -1; } c++; } console.log(arr1);
Performance comparison results ( https://jsperf.com/map-vs-reduce-vs-while-loop ):
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.