I want to merge value to array if it have a same id. I have one array of objects like this.
[
{
id: 'Tony',
type: 'hero',
favorite: 'Rosie',
},
{
id: 'Jane',
type: 'human',
favorite: null,
},
{
id: 'Tony',
type: 'hero',
favorite: 'Lisa',
},
{
id: 'Steve',
type: 'hero',
favorite: 'Jennie',
},
{
id: 'Tony',
type: 'hero',
favorite: 'Jisoo',
},
]
and I want to merge key favorite
from string to array. I want output like this
[
{
id: 'Tony',
type: 'hero',
favorite: ['Rosie', 'Lisa', 'Jisoo'],
},
{
id: 'Jane',
type: 'human',
favorite: null,
},
{
id: 'Steve',
type: 'hero',
favorite: ['Jennie'],
}
and i try to write code like this: (from: Sum similar keys in an array of objects )
var obj = [
{
id: 'Tony',
type: 'hero',
favorite: 'Rosie',
},
{
id: 'Jane',
type: 'human',
favorite: null,
},
{
id: 'Tony',
type: 'hero',
favorite: 'Lisa',
},
{
id: 'Steve',
type: 'hero',
favorite: 'Jennie',
},
{
id: 'Tony',
type: 'hero',
favorite: 'Jisoo',
},
];
var holder = {};
const ar = []
obj.forEach(function (d) {
if (holder.hasOwnProperty(d.id)) {
holder[d.id] = ar.push(holder[d.id] + d.favorite);
} else {
holder[d.id] = d.favorite;
}
});
var obj2 = [];
for (var prop in holder) {
obj2.push({ name: prop, favorite: holder[prop] });
}
console.log(obj2);
but out put is
[ { name: 'Tony', favorite: 2 },
{ name: 'Jane', favorite: null },
{ name: 'Steve', favorite: 'Jennie' } ]
How can i do this ?
You can do this with a single Array.reduce and would most likely be the most simple and performant approach:
var data = [ { id: 'Tony', type: 'hero', favorite: 'Rosie', }, { id: 'Jane', type: 'human', favorite: null, }, { id: 'Tony', type: 'hero', favorite: 'Lisa', }, { id: 'Steve', type: 'hero', favorite: 'Jennie', }, { id: 'Tony', type: 'hero', favorite: 'Jisoo', }, ] let result = data.reduce((r, {id,type,favorite}) => { r[id] = r[id] || {id, type, favorite: []} r[id].favorite.push(favorite) return r }, {}) console.log(Object.values(result))
The idea is to "group by" the id
and then keep pushing to the favorites
array on each iteration.
For ES5
you can do it in similar fashion:
var data = [ { id: 'Tony', type: 'hero', favorite: 'Rosie', }, { id: 'Jane', type: 'human', favorite: null, }, { id: 'Tony', type: 'hero', favorite: 'Lisa', }, { id: 'Steve', type: 'hero', favorite: 'Jennie', }, { id: 'Tony', type: 'hero', favorite: 'Jisoo', }, ] let result = data.reduce(function(r, c){ r[c.id] = r[c.id] || {id: c.id, type: c.type, favorite: []} r[c.id].favorite.push(c.favorite) return r }, {}) console.log(Object.values(result))
There really is no need for lodash
to achieve this.
Group by the id
with _.group()
, and then merge each group using _.map()
and _.mergeWith()
, and collect favorite
to an array:
const data = [{"id":"Tony","type":"hero","favorite":"Rosie"},{"id":"Jane","type":"human","favorite":null},{"id":"Tony","type":"hero","favorite":"Lisa"},{"id":"Steve","type":"hero","favorite":"Jennie"},{"id":"Tony","type":"hero","favorite":"Jisoo"}] const result = _(data) .groupBy('id') .map(g => _.mergeWith({}, ...g, (o, s, k) => { if(k !== 'favorite') return // non favorite key are not collected to an array if(_.isNil(s)) return o // don't add null or undefined to array return [].concat(o || [], s) // concat other values to array })) .value() console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
Just loop over the array and construct a new array after converting favorite
attribute into an array, then for next elements with the same id, push to favorite
array
let users = [{id: 'Tony', type: 'hero', favorite: 'Rosie',}, {id: 'Jane', type: 'human', favorite: null,}, {id: 'Tony', type: 'hero', favorite: 'Lisa',}, {id: 'Steve', type: 'hero', favorite: 'Jennie',}, {id: 'Tony', type: 'hero', favorite: 'Jisoo',},]; // To combine friends of the same user in an array at property friendNames let merged = {}; for (let user of users) { if (typeof merged[user.id] === 'undefined') { user.favorite = [user.favorite]; merged[user.id] = user; } else { merged[user.id].favorite.push(user.favorite) } } console.log(Object.values(merged));
Use map
and Set
to get this result.
First we create a new unique Set
using the id
field.
We seed a new new array
from this and call the map
method.
const arr = [ { id: 'Tony', type: 'hero', favorite: 'Rosie', }, { id: 'Jane', type: 'human', favorite: null, }, { id: 'Tony', type: 'hero', favorite: 'Lisa', }, { id: 'Steve', type: 'hero', favorite: 'Jennie', }, { id: 'Tony', type: 'hero', favorite: 'Jisoo', }, ]; const masterArr = [...new Set(arr.map((e) => e.id))].map(a => ({ id: a, type: arr.find(x => x.id === a).type, favorites: arr.filter(x => x.id === a).map(y => y.favorite) })); console.log(masterArr);
You can use reduce on the array.
const arr = [
{
id: 'Tony',
type: 'hero',
favorite: 'Rosie',
},
{
id: 'Jane',
type: 'human',
favorite: null,
},
{
id: 'Tony',
type: 'hero',
favorite: 'Lisa',
},
{
id: 'Steve',
type: 'hero',
favorite: 'Jennie',
},
{
id: 'Tony',
type: 'hero',
favorite: 'Jisoo',
},
]
const out = arr.reduce((result, el)=> {
const id = result.findIndex(e => e.id ===el.id)
if(id> -1){
result[id] = {...result[id], favorite: [...result[id].favorite, el.favorite]}
} else {result.push({...el, favorite: [el.favorite].filter(x => x) })}
return result
}, [])
console.log(out)
With Lodash:
var data = [ { id: 'Tony', type: 'hero', favorite: 'Rosie', }, { id: 'Jane', type: 'human', favorite: null, }, { id: 'Tony', type: 'hero', favorite: 'Lisa', }, { id: 'Steve', type: 'hero', favorite: 'Jennie', }, { id: 'Tony', type: 'hero', favorite: 'Jisoo', }, ] var result = _(data).groupBy(a => a.id).map((objs, key) => ({ 'id': key, 'type': _.head(objs).type, 'favorite': _.map(objs, 'favorite') })) .value(); console.log(result);
<script src="https://cdn.jsdelivr.net/lodash/4.17.2/lodash.min.js"></script>
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.