Use _.groupBy(), and then use _.mergeWith() to combine each group to a single object:
const data = [{"foo":"A","bar":[{"baz":"1","qux":"a"},{"baz":"2","qux":"b"}]},{"foo":"B","bar":[{"baz":"3","qux":"c"},{"baz":"4","qux":"d"}]},{"foo":"A","bar":[{"baz":"5","qux":"e"},{"baz":"6","qux":"f"}]},{"foo":"B","bar":[{"baz":"7","qux":"g"},{"baz":"8","qux":"h"}]}];
const result = _(data)
.groupBy('foo')
.map((g) => _.mergeWith({}, ...g, (obj, src) =>
_.isArray(obj) ? obj.concat(src) : undefined))
.value();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Answer from Ori Drori on Stack OverflowUse _.groupBy(), and then use _.mergeWith() to combine each group to a single object:
const data = [{"foo":"A","bar":[{"baz":"1","qux":"a"},{"baz":"2","qux":"b"}]},{"foo":"B","bar":[{"baz":"3","qux":"c"},{"baz":"4","qux":"d"}]},{"foo":"A","bar":[{"baz":"5","qux":"e"},{"baz":"6","qux":"f"}]},{"foo":"B","bar":[{"baz":"7","qux":"g"},{"baz":"8","qux":"h"}]}];
const result = _(data)
.groupBy('foo')
.map((g) => _.mergeWith({}, ...g, (obj, src) =>
_.isArray(obj) ? obj.concat(src) : undefined))
.value();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
You could filter and update the data with a hash table.
This proposal mutates the original data set.
var array = [{ foo: "A", bar: [{ baz: "1", qux: "a" }, { baz: "2", qux: "b" }] }, { foo: "B", bar: [{ baz: "3", qux: "c" }, { baz: "4", qux: "d" }] }, { foo: "A", bar: [{ baz: "5", qux: "e" }, { baz: "6", qux: "f" }] }, { foo: "B", bar: [{ baz: "7", qux: "g" }, { baz: "8", qux: "h" }] }],
hash = Object.create(null),
result = array.filter(function (o) {
if (!hash[o.foo]) {
hash[o.foo] = o.bar;
return true;
}
Array.prototype.push.apply(hash[o.foo], o.bar);
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Second 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>
Run code snippetEdit code snippet Hide Results Copy to answer Expand
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);
Run code snippetEdit code snippet Hide Results Copy to answer Expand
You can use _.map(), _.assign() and _.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}));
});
Fiddle Demo
Show code snippet
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>
Run code snippetEdit code snippet Hide Results Copy to answer Expand
You can use _.mergeWith() with array spread. When merging 2 values, check if the 1st (a) is still undefined (the empty object), if so return the 2nd item wrapped in an array, if it exists, use array spread to concat them:
const children = [{"orderName":"#1004"},{"orderName":"#1006"},{"orderName":"#1007"},{"orderName":"#1005"},{"deliveryDate":"25-25-25"},{"signature":"xq"}];
const result = _.mergeWith({}, ...children, (a, b) =>
_.isUndefined(a) ? [b] : [...a, b]
);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
Run code snippetEdit code snippet Hide Results Copy to answer Expand
If you don't use lodash, you can do like below.
const children = [
{ orderName: "#1004" },
{ orderName: "#1006" },
{ orderName: "#1007" },
{ orderName: "#1005" },
{ deliveryDate: "25-25-25" },
{ signature: "xq" },
];
const output = children.reduce((a, b) => {
const key = Object.keys(b)[0];
if (!a[key]) {
a[key] = [b[key]];
} else {
a[key].push(b[key]);
}
return a;
}, {});
console.log(output);
Run code snippetEdit code snippet Hide Results Copy to answer Expand
You can get the result using merge and keyBy lodash functions.
var array1 = [{id:1, name:'doc1'}, {id:2, name:'doc2'}];
var array2 = [{id:1, name:'doc1'}, {id:3, name:'doc3'}, {id:4, name:'doc4'}];
var merged = _.merge(_.keyBy(array1, 'id'), _.keyBy(array2, 'id'));
var values = _.values(merged);
console.log(values);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
Run code snippetEdit code snippet Hide Results Copy to answer Expand
Use _.unionBy() to combine two arrays, and remove duplicates that have the same unique field (id in this case). The lodash's union methods create an array of unique values. The _.unionBy() method accepts an iteratee which is invoked for each element of each array to generate the criterion by which uniqueness is computed.
const array1 = [{id:1, name:'doc1'}, {id:2, name:'doc2'}];
const array2 = [{id:1, name:'doc1'}, {id:3, name:'doc3'}, {id:4, name:'doc4'}];
const result = _.unionBy(array1, array2, 'id');
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
Run code snippetEdit code snippet Hide Results Copy to answer Expand
const output = input.reduce((res, {dates}) => res.concat(dates), []);
You may use reduce to iterate over the objects and concat the results together. Theres no need to use loadash at all.
Using Lodash
You can use _.map() to get an array of the date objects. To merge the objects to a single one, will use _.merge(). We'll use _.partial() to add a target object, so we won't mutate the original data. In addition, We'll use the _.spread() method on the _.merge(), so it can handle an array of objects:
var data = [{"id":1,"oid":5,"dates":{"5":{"start_date":"12.30","end_date":"12.31"},"14":{"start_date":"01.01","end_date":"01.15"}}},{"id":2,"oid":5,"dates":{"17":{"start_date":"02.01","end_date":"02.20"},"19":{"start_date":"03.01","end_date":"03.10"}}}];
var result = _.spread(_.partial(_.merge, {}))(_.map(data, 'dates'));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Using ES6
Pluck the dates by using Array#map on the Object#keys, and flatten by spreading into Object.assign:
var data = [{"id":1,"oid":5,"dates":{"5":{"start_date":"12.30","end_date":"12.31"},"14":{"start_date":"01.01","end_date":"01.15"}}},{"id":2,"oid":5,"dates":{"17":{"start_date":"02.01","end_date":"02.20"},"19":{"start_date":"03.01","end_date":"03.10"}}}];
var result = Object.assign({}, ...Object.keys(data).map((key) => data[key].dates));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
You can use _.mergeWith lodash method and pass custom function.
var a = {"beta":{"value":null,"error":null},"hamma":{"value":null,"error":null},"zerta":{"value":null,"error":null},"mozes":5}
var b = {"beta":5,"hamma":2, "mozes": 123}
_.mergeWith(a, b, function(aValue, bValue) {
_.isPlainObject(aValue) ? aValue.value = bValue : aValue = bValue
return aValue
})
console.log(a)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Here's a solution that iterates over the B array and uses set to update the value:
_.each(updates, (value, key) => _.set(data, `${key}.value`, value))
_.unionBy():
This method is like _.union except that it accepts iteratee which is invoked for each element of each arrays to generate the criterion by which uniqueness is computed. Result values are chosen from the first array in which the value occurs.
var original = [
{ label: 'private', value: 'private@johndoe.com' },
{ label: 'work', value: 'work@johndoe.com' }
];
var update = [
{ label: 'private', value: 'me@johndoe.com' },
{ label: 'school', value: 'schol@johndoe.com' }
];
var result = _.unionBy(update, original, "label");
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
Run code snippetEdit code snippet Hide Results Copy to answer Expand
Convert the lists to objects keyed by label, merge them by _.assign, and convert it back to an array. It will even retain order of the items on most browsers.
var original = [
{
label: 'private',
value: 'private@johndoe.com'
},
{
label: 'work',
value: 'work@johndoe.com'
}
];
var update = [
{
label: 'private',
value: 'me@johndoe.com'
},
{
label: 'school',
value: 'schol@johndoe.com'
}
];
console.log(
_.map(
_.assign(
_.mapKeys(original, v => v.label),
_.mapKeys(update, v => v.label)
)
)
);
// or remove more duplicated code using spread
console.log(
_.map(
_.assign(
...[original, update].map(
coll => _.mapKeys(coll, v => v.label)
)
)
)
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.js"></script>
Run code snippetEdit code snippet Hide Results Copy to answer Expand
This proposal does not alter the given data.
It creates new objects, first with just single data, later if more data should be grouped, it uses an array for batch and price.
var data = [{ product: 'ABC', productId: 'AB123', batch: 'BA1', price: '12' }, { product: 'ABC', productId: 'AB123', batch: 'BA2', price: '15' }, { product: 'XYZ', productId: 'AB124', batch: 'XY1', price: '124'}],
merged = [];
data.forEach(function (a) {
if (!this[a.productId]) {
this[a.productId] = { product: a.product, productId: a.productId, batch: a.batch, price: a.price };
merged.push(this[a.productId]);
return;
}
if (!Array.isArray(this[a.productId].batch)) {
this[a.productId].batch = [this[a.productId].batch];
}
if (!Array.isArray(this[a.productId].price)) {
this[a.productId].price = [this[a.productId].price];
}
this[a.productId].batch.push(a.batch);
this[a.productId].price.push(a.price);
}, Object.create(null));
console.log(merged);
Run code snippetEdit code snippet Hide Results Copy to answer Expand
You can make use of _.uniqWith to loop over the collection and get rid of duplicates. Apart from that, uniqWith grants you access to the objects themselves so you can tamper them as you like.
In this case, when a duplicate is found, I add its batch and price to the array of the original object, getting the desired result.
var arr = [{
product: 'ABC',
productId: 'AB123',
batch: 'BA1',
price: '12'
}, {
product: 'ABC',
productId: 'AB123',
batch: 'BA2',
price: '15'
}, {
product: 'XYZ',
productId: 'AB124',
batch: 'XY1',
price: '124'
}];
function addToArray(val1, val2) {
return _.isArray(val1) ? val1.concat(val2) : [val1].concat(val2);
}
function modifyObjs(a, b) {
b.batch = addToArray(b.batch, a.batch);
b.price = addToArray(b.price, a.price);
return true;
}
function predicateAndModifier(a, b) {
return a.product === b.product && a.productId === b.productId && modifyObjs(a, b);
}
console.log(_.uniqWith(arr, predicateAndModifier));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>
Run code snippetEdit code snippet Hide Results Copy to answer Expand
Create index object by indexing the arrays using _.keyBy('date'), merge the indexes, and extract the values using _.values():
const weather = [{"date":2,"weather":2},{"date":1,"weather":1},{"date":3,"weather":3}];
const power = [{"date":1,"power":10},{"date":2,"power":20}];
const weatherIndex = _.keyBy(weather, 'date');
const powerIndex = _.keyBy(power, 'date');
const result = _(powerIndex)
.pick(_.keys(weatherIndex))
.merge(_.pick(weatherIndex, _.keys(powerIndex)))
.values()
.value();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
While you have almost a solution with lodash, you could use in plain Javascript a proposal with a hash table and two loops for the arrays.
var weather = [{ date: 2, weather: 2 }, { date: 1, weather: 1 }, { date: 3, weather: 3 }],
power = [{ date: 1, power: 10 }, { date: 2, power: 20 }],
hash = new Map,
merged = power.map(a => {
var o = {};
Object.assign(o, a);
hash.set(a.date, o);
return o;
});
weather.forEach(a => hash.has(a.date) && Object.assign(hash.get(a.date), a));
console.log(merged);