-4

How can I sort by one key and deduplicate by another key in an array of object?

In my below example, there are multiple occurrences of same dist under same iD. How can I pick the smallest distance for a given id?

[ { dist: 1.2152494565059755, id: '37000' },
  { dist: 2.168068558345124, id: '9000' },
  { dist: 4.861213457464137, id: '37000' },
  { dist: 5.226238485876963, id: '04000' },
  { dist: 5.278968876845613, id: '29000' },
  { dist: 8.446987036894901, id: '09000' },
  { dist: 8.770432584510608, id: '09000' },
  { dist: 9.848816041209018, id: '04000' },
  { dist: 10.681310440202585, id: '58000' },
  { dist: 11.170746649119321, id: '58000' },
  { dist: 12.84374942857388, id: '37000' },
  { dist: 13.476922171827615, id: '09000' },
  { dist: 14.159308062885033, id: '09000' },
  { dist: 15.117353720958263, id: '80000' },
  { dist: 16.528082434902654, id: '58000' },
  { dist: 17.603866532406027, id: '80000' },
  { dist: 18.49748912990931, id: '37000' } ]

Expected output is

[ { dist: 1.2152494565059755, id: '37000' },
  { dist: 2.168068558345124, id: '09000' },
  { dist: 5.226238485876963, id: '04000' },
  { dist: 5.278968876845613, id: '29000' },
  { dist: 10.681310440202585, id: '58000' },
  { dist: 15.117353720958263, id: '80000' },
  { dist: 16.528082434902654, id: '58000' } ]
adiga
  • 34,372
  • 9
  • 61
  • 83
csvb
  • 365
  • 2
  • 6
  • 14
  • This site is full of examples of doing both operations. Please show what you have tried and what research efforts you have done. See [ask] – charlietfl Feb 02 '19 at 20:57
  • I tried deduplicating using https://www.npmjs.com/package/array-dedupe module but sorting using array.sort(). Not sure how to combine both to one file. – csvb Feb 02 '19 at 20:57
  • The site you are on ...Stackoverflow. It also has search box at top of every page and google and other search engines will also index answers here. Showing your attempts and doing basic research is expected when asking – charlietfl Feb 02 '19 at 20:59
  • I looked at this question where sorting was based on a key - https://stackoverflow.com/questions/8175093/simple-function-to-sort-an-array-of-objects/8175221#8175221. But I am not able to figure out how to deduplicate based on one key while sorting based on another key – csvb Feb 02 '19 at 21:03
  • [the PHP equivalent](https://stackoverflow.com/q/42281756/2943403) – mickmackusa Aug 22 '22 at 23:43

1 Answers1

1

You can achieve it with reduce and Object.values like this:

var array = [{dist:1.2152494565059755,id:'37000'},{dist:2.168068558345124,id:'9000'},{dist:4.861213457464137,id:'37000'},{dist:5.226238485876963,id:'04000'},{dist:5.278968876845613,id:'29000'},{dist:8.446987036894901,id:'09000'},{dist:8.770432584510608,id:'09000'},{dist:9.848816041209018,id:'04000'},{dist:10.681310440202585,id:'58000'},{dist:11.170746649119321,id:'58000'},{dist:12.84374942857388,id:'37000'},{dist:13.476922171827615,id:'09000'},{dist:14.159308062885033,id:'09000'},{dist:15.117353720958263,id:'80000'},{dist:16.528082434902654,id:'58000'},{dist:17.603866532406027,id:'80000'},{dist:18.49748912990931,id:'37000'}]
  
const merged = array.reduce((acc,a) =>{
  const id = parseInt(a.id);
  if(!acc[id] || acc[id]["dist"] > a.dist)
    acc[id] = a;
    
  return acc;
},{})

const final = Object.values(merged).sort((a,b) => a.dist - b.dist)

console.log(final)

Create an accumulator with each unique id as key and the object with smallest dist as value like this

{
   "37000": {
      "dist": 1.2152494565059755,
      "id": "37000"
   },
   "9000": {
      "dist": 2.168068558345124,
      "id": "9000"
   },
   .... and so on
}

Every time you loop through, check if the id already exists or the value of dist in the accumulator is bigger than the current item's dist. If yes, then update the accumulator. (parseInt() is required because "09000" and "9000" are considered as same id)

Then use Object.values to convert the values of accumulator object to an array and then finally sort it based on the dist value.

Update:

If Object.values isn't supported yet, you can map over Object.keys and get the values like this:

const final = Object.keys(merged).map(k => merged[k]).sort((a,b) => a.dist - b.dist)
adiga
  • 34,372
  • 9
  • 61
  • 83
  • thank you for answering. While trying to execute your solution, I am getting error at `Object.values` line. `Object.values is not a function`. – csvb Feb 03 '19 at 04:39
  • @csvb Updated the answer. – adiga Feb 03 '19 at 06:37
  • This worked well. Can you explain how these lines of code are functioning? mostly the accumulator and Object.Keys part. – csvb Feb 03 '19 at 17:35
  • @csvb I have added a detailed explanation in the answer. For accumulator, `Object.keys` and `Object.values`, click on the link on links in the answer. – adiga Feb 03 '19 at 18:26