cozysama cozysama - 2 months ago 11
Javascript Question

Returning values that only exist in two arrays of objects in vanilla JS?

I have two arrays of objects that contain a set of similar items

arr1 = [
{property1: 'foo', property2: 'bar', property3: 'baz'},
{property1: 'moo', property2: 'bar', property3: 'maz'}
]

arr2 = [
{property2: 'bar', property3: 'maz'},
{property2: 'bar', property3: 'santa'}
]


I need to write a function that takes the two object arrays as parameters. This function needs to return property1 of every object that matches the rest of the keys in array two.

so, my function should take the two arrays above and return only 'moo'. I've been at this for hours and can not seem to problem solve it correctly.

caveats: I would like to understand the solution without resorting to libraries, and I would like to solve it using a functional approach, without vars or for loops. hopefully using reduce() map() & filter() instead.

Answer

I've shortened property1, property2, and property3 to p1, p2, and p3 respectively.

You've given no indication that keys will vary amongst objects, so this solution assumes:

  • p1,p2,and p3 will always be present in arr1 objects
  • p2 and p3 will always be present in arr2 objects.

var arr1 = [
  {p1: 'foo', p2: 'bar', p3: 'baz'},
  {p1: 'moo', p2: 'bar', p3: 'maz'},
  {p1: 'zoo', p2: 'bar', p3: 'maz'} // added to show multiple outputs
];

var arr2 = [
  {p2: 'bar', p3: 'maz'},
  {p2: 'bar', p3: 'santa'}
];

const match = xs => ({p1, p2, p3}) =>
  xs.some(({p2:y, p3:z}) => p2 === y && p3 === z);

const prop = x => y => y[x];

var out = arr1.filter(match(arr2)).map(prop('p1'));

console.log(out);

Some will criticize that filter->map unnecessarily iterates through the array multiple times. You can combine the filtering and mapping in a single reduce but I think the readability suffers a little bit ...

var arr1 = [
  {p1: 'foo', p2: 'bar', p3: 'baz'},
  {p1: 'moo', p2: 'bar', p3: 'maz'},
  {p1: 'zoo', p2: 'bar', p3: 'maz'} // added to show multiple outputs
];

var arr2 = [
  {p2: 'bar', p3: 'maz'},
  {p2: 'bar', p3: 'santa'}
];

const match = xs => ({p1, p2, p3}) =>
  xs.some(({p2:y, p3:z}) => p2 === y && p3 === z);

var out = arr1.reduce((acc, x) => {
  if (match (arr2) (x))
    return [...acc, x.p1]
  else
    return acc
}, []);

console.log(out);

Mix/match the solutions to your heart's content.