I have a large javascript array of some people Bought a car in different years.
the simplified array is like this:
const owners = [{
name: "john",
hasCar: true,
yearBought: 2002
}, {
name: "john",
hasCar: true,
yearBought: 2005
}, {
name: "mary",
hasCar: true,
yearBought: 2015
}, {
name: "john",
hasCar: true,
yearBought: 2018
}]
if a person has more than one car (like John in this example), there is different objects for him with different years he has bought the car. I want to merge objects belongs to each individual person and the final result should be like this:
const owners = [{
name: "john",
hasCar: true,
yearBought: [2002, 2005, 2018]
}, {
name: "mary",
hasCar: true,
yearBought: 2018
}]
You could use reduce
the array and group them based on name
first. The accumulator is an object with each unique name
as key. If the name
already exists, use concat
to push them into the array. Else, create a new key in the accumulator and set it to the current object. Then, use Object.values()
to get the values of the array as an array
const owners = [{name:"john",hasCar:!0,yearBought:2002},{name:"john",hasCar:!0,yearBought:2005},{name:"mary",hasCar:!0,yearBought:2015},{name:"john",hasCar:!0,yearBought:2018}];
const merged = owners.reduce((r, o) => {
if(r[o.name])
r[o.name].yearBought = [].concat(r[o.name].yearBought, o.yearBought)
else
r[o.name] = { ...o };
return r;
},{})
console.log(Object.values(merged))
I hope this help using PURE lodash functions.. it looks clean and readable.
var array = [{
name: "john",
hasCar: true,
yearBought: 2002
}, {
name: "john",
hasCar: true,
yearBought: 2005
}, {
name: "mary",
hasCar: true,
yearBought: 2015
}, {
name: "john",
hasCar: true,
yearBought: 2018
}]
function mergeNames(arr) {
return Object.values(_.chain(arr).groupBy('name').mapValues((g) => (_.merge(...g, {
yearBought: _.map(g, 'yearBought')
}))).value());
}
console.log(mergeNames(array));
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
Thanks :)
You can group the items with a unique key (name
in your case), then map the groups, and merge the items in each group:
const { flow, partialRight: pr, groupBy, map, mergeWith, concat, isUndefined } = _
const mergeDuplicates = (isCollected, key) => flow(
pr(groupBy, key), // group by the unique key
pr(map, group => mergeWith({}, ...group,
(o, s, k) => isCollected(k) && !isUndefined(o) ? concat(o, s) : s
)) // merge each group to a new object
)
const owners = [{name:"john",hasCar:true,yearBought:2002},{name:"john",hasCar:true,yearBought:2005},{name:"mary",hasCar:!0,yearBought:2015},{name:"john",hasCar:true,yearBought:2018}]
const isCollected = key => key === 'yearBought'
const result = mergeDuplicates(isCollected, 'name')(owners)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
And the lodash/fp version:
const { flow, groupBy, map, mergeAllWith, cond, nthArg, concat } = _
const mergeDuplicates = (isCollected, key) => flow(
groupBy(key),
map(mergeAllWith(cond([[
flow(nthArg(2), isCollected),
concat,
nthArg(1)
]])))
)
const owners = [{name:"john",hasCar:!0,yearBought:2002},{name:"john",hasCar:!0,yearBought:2005},{name:"mary",hasCar:!0,yearBought:2015},{name:"john",hasCar:!0,yearBought:2018}]
const isCollected = key => key === 'yearBought'
const result = mergeDuplicates(isCollected, 'name')(owners)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>