2

Aim is to build a function, which takes an array of Objects as first arguments. As a second argument it takes a key and value pair.

function whatIsInAName(collection, source)

Now the function should return an array with all the matching keys and values from the object. For example:

whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" })´ 

should return

[{ first: "Tybalt", last: "Capulet" }]

And

whatIsInAName([{ "apple": 1, "bat": 2 }, { "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "bat": 2 })

should return

 [{ "apple": 1, "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }]

I tried looping through the collection- and through the source array searching for matches. Like this:

function whatIsInAName(collection, source) {
  // What's in a name?
  var arr = [];
  for (var i = 0; i < Object.keys(collection).length; i++) {
    for (var j = 0; j < Object.keys(source).length; j++) {
      if (collection[i].last === source.last) {
        arr.push(collection[i]);
      }
    }
  }
  console.log(arr);
}

And in case of this arguments whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" })

It not surprisingly works.

What I don't understand is, why I can't generalize the above solution, so that it also works in other cases.

Why is it not possible to simply give the condition:

if (collection[i] === source)

(Pls notice the missing "Last" key behind collection and source.)

When I console.log(source), console logs it. So imho the conditional statement above should work and should go to push the matches into the arr Array.

How can I build a function which returns an array with all the matching keys and values from the object.

 function whatIsInAName(collection, source)

And why does (collection[i] === source) not work?

Thank you.

S.H
  • 671
  • 2
  • 6
  • 22

3 Answers3

2

You need to iterate the key/value pairs and return a filtered result.

Actually there is not built-in method to test an object against another to check ig the object contains a sub object.

function whatIsInAName(collection, source) {
    var pairs = Object.entries(source);
    return collection.filter(object => pairs.every(([key, value]) => object[key] === value));
}

console.log(whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" }));
console.log(whatIsInAName([{ "apple": 1, "bat": 2 }, { "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "bat": 2 }));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

You can use filter and every. By object. So here the idea is

  1. Use filter on input arg to get desired element in output.
  2. In callback of filter by Object.keys we take the key out of matchObj arg and for each key we match value of element with the value we get in matchObj arg and filter accordingly.

console.log(whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" }))

function whatIsInAName(input,matchObj){
  return input.filter(e=> Object.keys(matchObj).every(el=> e[el] === matchObj[el]))
}
Code Maniac
  • 37,143
  • 5
  • 39
  • 60
1

First:

Why is it not possible to simply give the condition: if (collection[i] === source)

Because objects are compared by reference values, they are two different objects, so they references are distinct.

Now, you could fix you logic with something like this:

function whatIsInAName(collection, source)
{
  // What's in a name?

  var arr = [], sourceKeys = Object.keys(source);
  var toPush, key;

  // Iterate over the collection of input objects.

  for (var i = 0; i < collection.length; i++)
  {
    toPush = true;

    // Check if current analyzed object have all
    // required (key, value) pairs.

    for (var j = 0; j < sourceKeys.length; j++)
    {
      key = sourceKeys[j];

      if (!collection[i][key] || collection[i][key] !== source[key])
      {
        toPush = false;
        break;
      }
    }

    // If current object meet the condition, put it on the
    // result array.

    if (toPush)
      arr.push(collection[i]);
  }

  return arr;
}

let input1 = [
  {first: "Romeo", last: "Montague"},
  {first: "Mercutio", last: null},
  {first: "Tybalt", last: "Capulet"}
];

console.log(whatIsInAName(input1, {last: "Capulet"}));

let input2 = [
  {"apple": 1, "bat": 2},
  {"bat": 2},
  {"apple": 1, "bat": 2, "cookie": 2}
];

console.log(whatIsInAName(input2, {"apple": 1, "bat": 2}));
Shidersz
  • 16,846
  • 2
  • 23
  • 48