简体   繁体   中英

How can I de-dupe an array, and add additional properties to each object of the array based on its duplications

Let's say I have an array that looks like this:

[
  { id 1, date: "1/1/2021", count: 2, oldCount: 1 },
  { id 1, date: "2/1/2021", count: 3, oldCount: 2 },
  { id 2, date: "1/1/2021", count: 2, oldCount: 1 },
  { id 2, date: "2/1/2021", count: 3, oldCount: 2 }
]

The real key here is the combination of id and date . I want the final result to look like this:

[
  { id 1, "1/1/2021": 2, "2/1/2021": 3, "1/1/2021_old": 1, "2/1/2021_old": 2 },
  { id 2, "2/1/2021": 3, "2/1/2021": 3, "1/1/2021_old": 1, "2/1/2021_old": 2 }
]

I'd prefer to use lodash for this. The part that hangs me up is the additional properties to add to each object in the array. In our real world scenario, there could be several thousand records that need to be deduped and mapped, and this is resource intensive.

You can see the logic. It's grouping by id , and adding a property name based on the value of the original date property.

Here's a non-working example of my desired functionality:

arr = _.map(_.groupBy(data, "id"), objs => {              
  return _.assignWith({ /* I don't know the dates to set the property names */ }, ...objs)
});

I can do this with nested loops. I'm looking for best performance options and less lines of code.

Group by id , map the groups, and then map each group. When mapping the objects of the group, create a new object with the [date] and [`${}_old`] keys with the respective values, and then use _.merge() with array spread to merge all objects to a single one.

 const arr = [{"id":1,"date":"1/1/2021","count":2,"oldCount":1},{"id":1,"date":"2/1/2021","count":3,"oldCount":2},{"id":2,"date":"1/1/2021","count":2,"oldCount":1},{"id":2,"date":"2/1/2021","count":3,"oldCount":2}] const result = _.map( _.groupBy(arr, 'id'), group => _.merge( {}, ..._.map(group, ({ id, date, count, oldCount }) => ({ id, [date]: count, [`${date}_old`]: oldCount })) ) ) 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"></script>

And the same idea with lodash/fp, using _.flow() to generate a more readable function, and to merge all items ig a group using _.mergeAll() :

 const { flow, groupBy, map, mergeAll } = _ const fn = flow( groupBy('id'), map(flow( map(({ id, date, count, oldCount }) => ({ id, [date]: count, [`${date}_old`]: oldCount })), mergeAll )) ) const arr = [{"id":1,"date":"1/1/2021","count":2,"oldCount":1},{"id":1,"date":"2/1/2021","count":3,"oldCount":2},{"id":2,"date":"1/1/2021","count":2,"oldCount":1},{"id":2,"date":"2/1/2021","count":3,"oldCount":2}] const result = fn(arr) console.log(result)
 <script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>

A simple Array.reduce should produce what you need -- no library or external dependencies necessary and still very brief.

 const input = [ { id: 1, date: "1/1/2021", count: 2, oldCount: 1 }, { id: 1, date: "2/1/2021", count: 3, oldCount: 2 }, { id: 2, date: "1/1/2021", count: 2, oldCount: 1 }, { id: 2, date: "2/1/2021", count: 3, oldCount: 2 } ]; const output = Object.values(input.reduce((a, c) => { a[c.id] = a[c.id] || {id: c.id}; a[c.id][c.date] = c.count; a[c.id][`${c.date}_old`] = c.oldCount; return a; }, {})); console.log(output);

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM