0

I have two arrays of objects and need to find the intersection (objects with same id) in each, and return the intersecting object instance with the lowest score.

This is related to Simplest code for array intersection in javascript but with additional needs to evaluate an attribute on the intersecting items.

array1 = [
  {id:'aaa',score:5},
  {id:'bbb',score:5},
  {id:'ccc',score:20},
  {id:'xxx',score:1},
  {id:'yyy',score:1},
  {id:'zzz',score:20},
]
array2 = [
  {id:'aaa',score:1},
  {id:'bbb',score:1},
  {id:'ccc',score:5},
  {id:'zzz',score:60},
]

Finding the intersection by object.id is fairly easy:

shared = array1.filter(a => array2.some(b => a.id === b.id)); 

But that would return the items in array1 that have common items in array2. What I really want to do is return the intersecting objects with the lowest score.

Desired result:

shared = [
  {id:'zzz',score:20},
  {id:'ccc',score:5},
  {id:'aaa',score:1},
  {id:'bbb',score:1}
]

Is there a good way to do this in a single function?

I also need to sort the resulting array sorted by score and then id, but I can probably do that afterwards.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
byron
  • 984
  • 3
  • 14
  • 26
  • ```comparator = function (a, b) { if(a.id === b.id) { return a.score = Math.min(a.score, b.score); } }; shared = array1.filter(a => array2.some(b => comparator(a, b))); ``` – David F Dec 23 '22 at 19:51

2 Answers2

1

You can use a similar method, but with Array#flatMap and Array#find.

let array1 = [
  {id:'aaa',score:5},
  {id:'bbb',score:5},
  {id:'ccc',score:20},
  {id:'xxx',score:1},
  {id:'yyy',score:1},
  {id:'zzz',score:20},
],
array2 = [
  {id:'aaa',score:1},
  {id:'bbb',score:1},
  {id:'ccc',score:5},
  {id:'zzz',score:60},
];
let res = array1.flatMap(x => {
  let o = array2.find(y => y.id === x.id);
  return o ? {id: x.id, score: Math.min(x.score, o.score)} : [];
});
console.log(res);
Unmitigated
  • 76,500
  • 11
  • 62
  • 80
1

Unmitigated's solution does the job.
Here is an approach using reduce and find

const array1 = [
  {id:'aaa',score:5},
  {id:'bbb',score:5},
  {id:'ccc',score:20},
  {id:'xxx',score:1},
  {id:'yyy',score:1},
  {id:'zzz',score:20},
]
const array2 = [
  {id:'aaa',score:1},
  {id:'bbb',score:1},
  {id:'ccc',score:5},
  {id:'zzz',score:60},
]


const shared = array1.reduce((acc,curr) => {
  const o = array2.find(e => e.id === curr.id)
  return o ? [...acc,{id: curr.id, score: Math.min(curr.score,o.score)}]: acc;
},[])

console.log(shared)

sorting is also straightforward

const array1 = [  {id:'aaa',score:5},  {id:'bbb',score:5},  {id:'ccc',score:20},  {id:'xxx',score:1},  {id:'yyy',score:1},  {id:'zzz',score:20},]
const array2 = [  {id:'aaa',score:1},  {id:'bbb',score:1},  {id:'ccc',score:5},  {id:'zzz',score:60},]


const shared = array1
.reduce((acc,curr) => {
  const o = array2.find(e => e.id === curr.id)
  return o ? [...acc,{id: curr.id, score: Math.min(curr.score,o.score)}]: acc;
},[])
.sort((a,b) => b.score - a.score || a.id.localeCompare(b.id))

console.log(shared)
cmgchess
  • 7,996
  • 37
  • 44
  • 62
  • Thanks. I accepted Unmitigated's answer since he posted first. Both solutions work. Really appreciate it. – byron Dec 23 '22 at 23:25