0

Question

Make a function that looks through an array of objects (first argument) and returns an array of all objects that have matching name and value pairs (second argument). Each name and value pair of the source object has to be present in the object from the collection if it is to be included in the returned array.

For example, if the first argument is [{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], and the second argument is { last: "Capulet" }, then you must return the third object from the array (the first argument), because it contains the name and its value, that was passed on as the second argument.

My Attempt

function whatIsInAName(collection, source) {

let filteredCollection = collection.filter((item)=>{
  return collection[item].indexOf((source[item])> 0);

})
  return filteredCollection;
}



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

My Question

I really struggled to loop through the objects and find the relevant keys and values at the same time. It seems certain functions do not work on objects as they do with Arrays.

Your help is appreciated greatly with fixing this code problem?

AndrewNeedsHelp
  • 385
  • 4
  • 15
  • 3
    [`Object.entries(obj)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries) gives you an array of key/value pairs for an obj. – ASDFGerte Apr 29 '20 at 13:09
  • Also the brackets around `indexOf` are messed up, the line won't do what you think it does. – Jonas Wilms Apr 29 '20 at 13:18
  • How do you then change back to an object? – AndrewNeedsHelp Apr 29 '20 at 13:18
  • @AndrewNeedsHelp You don't need to change back to an object actually. You still just need to `filter` the `collection`, that part of the code is right. But then, you need to [loop through `source`](https://stackoverflow.com/q/684672/1048572) to find whether all its properties are in the current `item` – Bergi Apr 29 '20 at 13:19
  • so is it just the brackets that is wrong? If so how should they be? @Bergi – AndrewNeedsHelp Apr 29 '20 at 13:20
  • function whatIsInAName(collection, source) { let filteredCollection = collection.filter((item)=>{ return collection[item].indexOf(source[item])> 0; }) return filteredCollection; } // TypeError: Cannot read property 'indexOf' of undefined – AndrewNeedsHelp Apr 29 '20 at 13:21
  • @AndrewNeedsHelp No, it's not just the brackets. Neither `collection[item]` nor `indexOf` makes sense here. `item` is one of the objects in the array, and you need to compare it to the `source`. – Bergi Apr 29 '20 at 13:33

1 Answers1

2

A few issues:

  • (source[item])> 0 is a boolean expression, so you are actually doing .indexOf(true) or .indexOf(false), neither of which makes sense.
  • indexOf can find a given object in the array, but it cannot be used to find array elements which meet some condition, which is really what you want. You should use another method.
  • As it seems the second argument can have several properties that must match, you need somewhere a loop that iterates over those properties. There is no such loop in your code.

You could do it like this:

function whatIsInAName(collection, source) {
    let filteredCollection = collection.filter((item) => {
        return Object.entries(source).every(([key, value]) => {
             return item[key] === value;
        });
    });
    return filteredCollection;
}

let result = whatIsInAName([{ first: "Romeo", last: "Montague" }, 
                            { first: "Tybalt", last: "Capulet" }], 
                           { last: "Capulet" });
console.log(result);

Note that you can use the shorter arrow function syntax where there is no code block, but just an expression.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • 1
    This is fascinating, so if you enter [key, value] as you have here. Then you can iterate through both sides of the array that you created (with Object.entries()) at the same time!? I had no idea this was possible – AndrewNeedsHelp May 02 '20 at 12:22
  • function whatIsInAName(collection, source) { var arr = []; for(let [key, value] of Object.entries(collection)){ let filteredEntries = [key, value].filter((item)=>{ return item.key == source.key && item.value == source.value }) arr.push(filteredEntries); } return arr; } - your solution was perfect, I tried a variation, but doesn't seem to work. If you have an insight into what might be wrong that would be greatly appreciated – AndrewNeedsHelp May 08 '20 at 13:24
  • `[key, value].filter` will filter that new array with 2 values: key and value. That is not what you want ;-) – trincot May 08 '20 at 13:54