Got very interesting code in the answers. I would like to mention that I also could achieve the result using the lodash method .merge().
const result = _.merge(listOfQuestions, listOfAnswers)
const listOfQuestions = [{question1:{important: true}}, {question2:{important: false}}]
const listOfAnswers = [{question1:{answer: false}}, {question2:{answer: true}}]
const result = _.merge(listOfQuestions, listOfAnswers)
console.log(result)
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"></script>
Run code snippetEdit code snippet Hide Results Copy to answer Expand
Answer from Phoenix on Stack OverflowMerge JavaScript objects in array with same key - Stack Overflow
javascript - Merge 2 object with same key, value from 2 array - Stack Overflow
arrays - ES6 / JavaScript - How to merge an object on a specific key - Stack Overflow
Combining the content of multiple objects that have the same key with that key as the property in JavaScript - Stack Overflow
What does the learnwithparam blog cover?
How do I follow new posts?
How often are new posts published?
Got very interesting code in the answers. I would like to mention that I also could achieve the result using the lodash method .merge().
const result = _.merge(listOfQuestions, listOfAnswers)
const listOfQuestions = [{question1:{important: true}}, {question2:{important: false}}]
const listOfAnswers = [{question1:{answer: false}}, {question2:{answer: true}}]
const result = _.merge(listOfQuestions, listOfAnswers)
console.log(result)
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"></script>
Run code snippetEdit code snippet Hide Results Copy to answer Expand
You could collect the inner properties of every question in an object and render a new object with only one question in a new array.
const
setHash = o => Object.entries(o).forEach(([k, v]) => Object.assign(hash[k] = hash[k] || {}, v));
var listOfQuestions = [{ question1: { important: true } }, { question2: { important: false } }],
listOfAnswers = [{ question1: { answer: false } }, { question2: { answer: true } }],
hash = Object.create(null),
result;
listOfQuestions.forEach(setHash);
listOfAnswers.forEach(setHash);
result = Object.entries(hash).map(([k, v]) => ({ [k]: v }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Run code snippetEdit code snippet Hide Results Copy to answer Expand
Here is one option:-
var array = [{
name: "foo1",
value: "val1"
}, {
name: "foo1",
value: ["val2", "val3"]
}, {
name: "foo2",
value: "val4"
}];
var output = [];
array.forEach(function(item) {
var existing = output.filter(function(v, i) {
return v.name == item.name;
});
if (existing.length) {
var existingIndex = output.indexOf(existing[0]);
output[existingIndex].value = output[existingIndex].value.concat(item.value);
} else {
if (typeof item.value == 'string')
item.value = [item.value];
output.push(item);
}
});
console.dir(output);
Here is another way of achieving that goal:
var array = [{
name: "foo1",
value: "val1"
}, {
name: "foo1",
value: [
"val2",
"val3"
]
}, {
name: "foo2",
value: "val4"
}];
var output = array.reduce(function(o, cur) {
// Get the index of the key-value pair.
var occurs = o.reduce(function(n, item, i) {
return (item.name === cur.name) ? i : n;
}, -1);
// If the name is found,
if (occurs >= 0) {
// append the current value to its list of values.
o[occurs].value = o[occurs].value.concat(cur.value);
// Otherwise,
} else {
// add the current item to o (but make sure the value is an array).
var obj = {
name: cur.name,
value: [cur.value]
};
o = o.concat([obj]);
}
return o;
}, []);
console.log(output);
Use a lodash chain to concat the arrays, group similar objects, and then merge each group to a single object:
var arr1 = [{ a: "a", 1: 1, 2: 2 }, { a: "b", 1: 1, 2: 3 }];
var arr2 = [{ a: "a", 3: 123 }, { a: "b", 3: 4411 }];
var result = _(arr1)
.concat(arr2) // concat the 2nd array
.groupBy('a') // group by the identical key
.map(_.spread(_.curry(_.merge, {}))) // left currey merge to to create a new empty object, and spread the group as parameters
.value();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
With ES6 you can use Array#reduce to collect the similar objects in a Map, then get the Map#values iterator, and use the spread syntax to convert to an array:
const arr1 = [{ a: "a", 1: 1, 2: 2 }, { a: "b", 1: 1, 2: 3 }];
const arr2 = [{ a: "a", 3: 123 }, { a: "b", 3: 4411 }];
const result = [...arr1.concat(arr2) // concat the arrays
.reduce((m, o) => m.set(o.a, Object.assign(m.get(o.a) || {}, o)), // use a map to collect similar objects
new Map()
).values()]; // get the values iterator of the map, and spread into a new array
console.log(result);
you can do
var arr1 = [
{ a: "a", 1: 1, 2: 2 },
{ a: "b", 1: 1, 2: 3 }
];
var arr2 = [
{ a: "a", 3: 123 },
{ a: "b", 3: 4411 }
];
let result = arr1.map((e) => {
for(let element of arr2){
if(e.a == element.a) Object.assign(e, element);
}
return e;
});
console.log(result);
Here the solution using lodash and uniqWith function: JSFiddle.
Here's the code:
function merge(array) {
return _.uniqWith(array, compareAndMerge)
}
function compareAndMerge(first, second) {
if (first.field === second.field) {
first.values = second.values = [].concat(first.values, second.values)
return true
}
return false
}
var data = [{
field: 'Currency',
operator: 'IN',
values: ['usd']
}, {
field: 'Currency',
operator: 'IN',
values: ['gbp']
}, {
field: 'Amount',
operator: 'IN',
values: [2]
},
{
field: 'Amount',
operator: 'IN',
values: [3]
}]
console.log(merge(data))
Lodash.uniqWidth function wants an array and a comparator. In case of equal fields we edit values of the two compared elements assigning the concatenation of the two values arrays.
Something more: it's a transgression to edit objects inside the comparator, but I think that it could run safely.
Sounds like you are looking to combine concepts of merging objects and concatenating arrays along the way.
Using vanilla ES6 (probably far from optimal in terms of performance):
const one = {field: "currency", values: ["USD"]};
const two = {field: "currency", values: ["GBP"]};
const mergeConcat = (obj1, obj2) => {
const result = {...obj1, ...obj2};
Object.keys(obj1).map(key => {
if (Object.keys(obj2).includes(key) && Array.isArray(obj1[key])) {
result[key] = obj1[key].concat(obj2[key]);
}
})
return result;
}
console.log(mergeConcat(one, two))
// { field: 'currency', values: [ 'USD', 'GBP' ] }
Run code snippetEdit code snippet Hide Results Copy to answer Expand
Using lodash (almost directly from their docs):
const customizer = (objValue, srcValue) => {
if (_.isArray(objValue)) {
return objValue.concat(srcValue);
}
}
const one = {field: "currency", values: ["USD"]};
const two = {field: "currency", values: ["GBP"]};
console.log(_.mergeWith(one, two, customizer))
// { field: 'currency', values: [ 'USD', 'GBP' ] }
Run code snippetEdit code snippet Hide Results Copy to answer Expand
You can iterate over the object keys and create a new object out of their aggregation.
You can use ES6 spread operator (...) which allows us to quickly copy all or part of an existing array or object into another array or object.
const cat1 = { med1: { a: 10, b: 12 }, med2: { c: 14, d: 16 } };
const cat2 = { med1: { e: 18, f: 20 }, med2: { g: 22, h: 24 } };
let resultObject = {};
Object.keys(cat1).map(key => { // iterate over the keys
resultObject = {
...resultObject,
[key]: {...cat1[key], ...cat2[key]} // merge two objects
}
return;
});
console.log(resultObject);
For combining two objects with a single level of indirection 👇
const cat1 = { med1: { a: 10, b: 12 }, med2: { c: 14, d: 16 } }
const cat2 = { med1: { e: 18, f: 20 }, med2: { g: 22, h: 24 } }
const merge = (o1, o2) =>
Object.keys(o1)
.reduce((p, key) =>
(p[key] = { ...o1[key], ...o2[key] }, p), {})
console.log(merge(cat1, cat2))