1

JavaScript - Intermediate Algorithm Scripting

I am trying to make a JavaScript function to look through an array of objects (first argument) and return an array of all objects that have matching property and value pairs.

Although the correct solution is given at freeCodeCamp, I would like to know what are the problems and errors in my code. Also, I found a solution on stack overflow, but I am not getting what's wrong with my code.


Here's my code

function whatIsInAName(collection, source) {
  // What's in a name?
  var arr = [];
  // Only change code below this line
  var obj;
  var prop;
  var keys = Object.keys(source);
  for (var i = 0; i < collection.length; i++) {
    for (var j = 0; j < Object.keys(source).length; j++) {
      obj = collection[i];
      prop = Object.keys(source)[j];
      if (obj.hasOwnProperty(prop) && obj.prop === source.prop) {
        arr = arr.concat([obj]);
      }
    }
  }
  // Only change code above this line
  return arr;
}

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

Here is the result I am getting

[{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }]

Instead of

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

Kristianmitk
  • 4,528
  • 5
  • 26
  • 46
Ayudh Khajne
  • 55
  • 1
  • 7
  • This code is running without any runtime error. But the result is not as expected. – Ayudh Khajne Apr 30 '18 at 12:32
  • You may want to have a look at [Array.prototype.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) how you can use it is shown in [this answer](https://stackoverflow.com/a/50075368/1641941) If you need help I can add an answer here using your data and filter(s) you need. – HMR Apr 30 '18 at 12:48

2 Answers2

4

In your if-statement you need to have obj[prop] === source[prop] instead of obj.prop === source.prop. See computed property names.

As both objects don't contain a property prop the conditions evaluates always to true (undefined === undefined is true).


Demo

(note I moved obj = collection[i]; to the outer loop as its superfluous to assign it every time in the inner one)

function whatIsInAName(collection, source) {
  // What's in a name?
  var arr = [];
  // Only change code below this line
  var obj;
  var prop;
  var keys = Object.keys(source);
  for (var i = 0; i < collection.length; i++) {
    obj = collection[i];
    for (var j = 0; j < Object.keys(source).length; j++) {
      prop = Object.keys(source)[j];
      if (obj.hasOwnProperty(prop) && obj[prop] === source[prop]) {
        arr = arr.concat([obj]);
      }
    }
  }
  // Only change code above this line
  return arr;
}

let res = whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" });

console.log(res)
Kristianmitk
  • 4,528
  • 5
  • 26
  • 46
2

[Kristianmitk apparently added some explanation at the same time I was writing this, but I'll leave this answer here as well, in case the alternative explanation is useful to anyone...]


What Kristianmitk says is correct, but perhaps could use some explanation.

The reason your code returns every element is that in each case, you end up checking

if (/*...*/ && obj.prop === source.prop) {
    //...
}

But obj.prop means "the property named prop"; that is, you would use it to find the value "xyzzy" of an object declared like

{ prop: "xyzzy" }

What you want is to check the property named by the value of the variable prop. That's done using the [] operator.

var prop = "foo";
var obj = { prop: "nope" , foo: "found it" };

// these are true:
obj.prop === "nope"
obj[prop] === "found it"

In your test case, since none of the objects in question have a prop property, all values are undefined. And because JavaScript is being dynamic, it's fine to reference those undefined values (no error). And because JavaScript was written by heathens, undefined === undefined is true.

There are other ways the code could be improved (for readability), but I think that's the only one that keeps it from working properly. The next thing I'd look at is, even after you've said

var keys = Object.keys(source);

you later repeatedly make additional calls to Object.keys(source) when you could just say keys. This is not, as some will claim, a question of what's "efficient". At one time using the variable was definitely more efficient, and maybe it still is, but caring about optimization at that level is not a good idea. Caring about readability is a good idea, though, and once you've given the keys array a nice, simple name (keys) you should use it.

Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52