Is filter only solution here in task

Hi,

I am trying to solve the task - https://www.freecodecamp.org/challenges/wherefore-art-thou
and when after many hours i was stuck on one point to be able to loop through and find the way to see if there is a match between source and collection - my jsfiddle here - https://jsfiddle.net/jinisner/2nsw4deh/

I am able to get values from both but do not know how to check if one’s value set exists in other …

But to my disappointment when i saw hint despite there is no mention of hind all 3 solutions use filter , now i still cannot understand it …Is there no other way in javascript to loop using a for loop and find if an object has values that we want and give us out put …

Kindly guide… I ask as i do not want to cram up the solution and then change my thinking as per solution but have my own solution …

Adding my jsfiddle code for convinience–

////////////-----------------------------------
function whatIsInAName(collection, source) {
  // What's in a name?
  var arr = [];
 
  for (var key in collection){
  if(collection.hasOwnProperty(key)){
  console.log(collection[key]);
  }
  }
  
 
  
  
  // Only change code above this line
  return arr;
}

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

////////------------------------------------------------

Thanks

Regards

collection is an array of objects …

Just a little bit of help to see if you can understand … and let you create your own solution with for loops … i used for loop probably as i didnt know filters at the time.

for (var key in collection[0]) {
 console.log(collection[0][key]);
console.log(key)
}
1 Like

@JohnL3 - thanks - i am getting there -



for(var i = 0; i < collection.length;i++){
   var src = source[key];
  for (var key in collection[i]) {
  if(collection[i][key]===source[key]){
  
  arr.push(collection[i]);
// console.log(arr);
 }

}

}

Now 2 conditions are satisfied, will get back to you soon …

Regards

@JohnL3 - Hi , i am really stuck at not being able to loop through in case of more then one property value in the object source - like here - { “a”: 1, “b”: 2 }

So if there is one value like - { “a”: 1 } i made some changes to code you have suggested and it works , but i tried using .hasOwnPropety etc and its not giving right results- my current code is here - can you please guide as to what i can do to be able to compare more then one property value …

Thanks


function whatIsInAName(collection, source) {
  // What's in a name?
  var arr = [];
  // Only change code below this line
  for(var i = 0; i < collection.length;i++){
   var src = source[key];
  for (var key in collection[i]) {
  if(collection[i][key]===source[key]){
    
  
  arr.push(collection[i]);
// console.log(arr);
 }

}

}
  
  // Only change code above this line
  return arr;
}

whatIsInAName([{ "a":

1, “b”: 2 }, { “a”: 1 }, { “a”: 1, “b”: 2, “c”: 2 }], { “a”: 1, “b”: 2 }) ;

I think the Object.keys() and map() methods may help you. :slight_smile:

const obj = {a: 1, b: 2};
const keys = Object.keys(obj); // keys = ["a", "b"]
const values = keys.map(key => obj[key]); // values = [1, 2]

You can also simply chain them together like this depending on your use case:


const values = Object.keys(obj).map(key => obj[key]);

It’s worth noting that this isn’t limited to the map() method. filter() and reduce() may come in handy depending on what you do.

Good luck. :slight_smile:

EDIT: Added example. Changed funny-reading sentence.

1 Like

@honmanyau - thanks , so where i be using this , like here -

I am using this right now -

for(var i = 0; i < collection.length;i++){
   var src = source[key];
  for (var key in collection[i]) {
  if(collection[i][key]===source[key]){
    
  
  arr.push(collection[i]);
// console.log(arr);
 }

}

}

So i tried using it like -

 for (var key in collection[i]) {
  if(Object.keys(collection)===Object.keys(source)){

but its not giving any results, i am really sorry but i am very new to this ...

Regards

Don’t forget the power of proper indentation when showcasing code and you have a single line that I have commented-out below which would cause error based on the code you pasted. Sorry I don’t have the full solution for you but I hope this helps a little :slight_smile:

function whatIsInAName(collection, source) {
  // What's in a name?
  var arr = [];
  // Only change code below this line
  for(var i = 0; i < collection.length;i++){

  //Key is not defined at this point so it would break the application
  //Remove this line:
  //var src = source[key]; 
  
  for (var key in collection[i]) {
    //This statment says that if any of the keys match then add it to the result array.
    //The problem definition states that all keys must match. 
    //This is why the code that you have passes the first two test 
   //cases where there are no objects that contain a partial result. 
    if(collection[i][key]===source[key]){ 
      arr.push(collection[i]); 
    }
    //Instead you need to only push items to the array when all of the attributes 
    //in the source match attributes in the collection
  }

}  
  
  // Only change code above this line
  return arr;
}

whatIsInAName([{ "a": 1, "b": 2 }, { "a": 1 }, { "a": 1, "b": 2, "c": 2 }], { "a": 1, "b": 2 });
1 Like

@HassanM - thanks for this amazing reply , i am however still confused at one point -


 for(var i = 0; i < collection.length;i++){
  var src = source;
  for (var key in collection[i]) {
  if(collection[i]===src){
   arr.push(collection[i]);

 }

}

}

If i am doing console.log(collection[i]); it gives value of each object from index 0 onwards, same way if i use console.log(source) it gives values of source object , but when i am comparing it here , its returning an empty array…

Is this the right way to compare 2 objects … and if not this slight change of comparing collection[i] and src, why is it not working , src is the variable that holds source …

Thanks again …

@jinisner There are some problems with your code snippet:

  • You are right, this is not the right way to compare two objects because you are not comparing the value of the objects. Instead the default equal operator(== & ===) in JavaScript will only return true if both objects refer to the same location in memory. Which in your case they are not.
    An example would be:
var x = {};
var y = {};
var z = x;

x === y; // => false
x === z; // => true

Here is a link where I got this snippet and explaining the challenge of comparing two objects in such a generic manner. Stack Overflow: how to determine object equality

  • The other thing is that the logic you are trying to do is wrong, {a:1, b:2 }, {a: 1} => this should be added to the final list even though they are not exactly equal. The question says that everything in the source is available in the collection. This makes it easier for you.

  • Why does it make it easier? Because you only have to iterate over the keys of the source and fetch that from each object on the collection and see if it matches the value of the corresponding key in the source. if it returns undefined then you know its not there if it return a value then you check that.

P.S. Press on with Object.Keys, iterate over all keys and try and translate what I said to code first and then have a read in Stackoverflow about it all.

2 Likes

@HassanM Just beat me to it with an excellent response. :stuck_out_tongue: I thought I’d still post what I typed particularly because of the second code example, which may save you time in the future.

The problem here is that you can’t you can’t simply compare two object literals like that in Javascript. Consider that you have two boxes, one box has an apple and an orange inside it; the other box has an apple in it. The two boxes are clearly different—just as {a: 1, b: 2} is clearly different to {a: 1}, and therefore {a: 1, b: 2} === {a: 1} will return false.

In fact, in Javascript the following will also return false:

    const nya = {a: 1};
    const nyu = {a: 1};

    console.log(nya === nyu); // false

This is because the objects are placed in different parts of the computer’s memory and nya and nyu are references to them.

It may be clearer if you consider the following example:

    const nya = {a: 1};
    const nyu = {a: 1};
    const nyo = nyu;

    nyu.a = 2;

    console.log(nya); // {a: 2}
    console.log(nyu); // {a: 2}
    console.log(nyo); // {a: 2}
    console.log(nya === nyu); // false
    console.log(nya === nyo); // false
    console.log(nyu === nyo); // true

I think it may be worthwhile forgetting about the code you have written for a while, and take some time to think about the logic, by breaking the problem into smaller steps that you can digest, behind whatever code you are going to write. Try [[{a: 1}], {a: 1}], [[{a: 1, b: 2}], {a: 1}], [[{a: 1}], {a: 1, b: 2}] and [[{a: 1, b: 2}], {a: 1, b: 2}] first. :slight_smile:

2 Likes

@HassanM , @honmanyau - As has been suggested i went through the code from start and studies Object.keys() , Object , after the that i was able to find the values and keys separately like here –


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

 }

 console.log(source);
 console.log(Object.keys(source));

  // Only change code above this line
  return arr;
}

whatIsInAName([{ "a": 1, "b": 2 }, { "a": 1 }, { "a": 1, "b": 2, "c": 2 }], { "a": 1, "b": 2 });

But i have no clue as to how i can use the info as i do not think that arrays can be compared like strings, is this the right way to proceed or am i doing something wrong here …

Thanks …

@jinisner Think about it like this:

ForEach currentKeyFromSource in Object.keys(Source) => Check does current Object in collection match the following:

  • Collection[i][currentKeyFromSource] === Undefined => this means this Object in the collection does not have the item. If this is false then we can check the next thing.

  • Collection[i][currentKeyFromSource] === Source[currentKeyFromSource] => we are checking the value now do they match great we can carry on looping. If they don’t lets break out of the loop no need to check any more but its too early to add it to the result because it needs to match each key from the Source.Keys.

Can you now think who should be in the outer loop? We don’t care that all props in the collection objects match its the other way around.

@HassanM - So the task wants me to find out if inside an array of objects if there are any objects that contain a certain property value pair/pairs…

But if i do not want to use filter function , i can get the values but cannot compare them as object cannot be compared as strings, same way even if i get them returned as arrays , i still am not able to find a way to loop inside collection and check for values similar to that of source …

You have a clear understanding so it must be real easy for you but here when you say -

ForEach currentKeyFromSource in Object.keys(Source)

Do you mean - Object.keys(source) which returns array - Array [ “a”, “b” ]

Then when you say Collection[i][currentKeyFromSource] this returns

Array [ “a”, “b” ]
Array [ “a” ]
Array [ “a”, “b”, “c” ]

But why are you calling currentKeyFromSource and what value it has like source[i] or something else ? Will i have to run a separate loop for it ?

The second bullet point again i cannot understand why we are using currrentKeyFromSource and will its value be Object.keys(Source)

I am really sorry but i can think in a very simple manner and hence struggling with some logic here …

Regards

1 Like

Try the following code where you take collection[1][“a”] this will return two thing either the value of “a” or undefined if the object in the collection does not have that property defined. Now you can take that check and put it inside the for loop over source keys and I think that is your solution. Just remember everything in source has to match not just a single property.

Please don’t apologise about, its really normal to find these kinds of problems really challenging I struggle plenty as well.

Best Regards,

P.S. Filter is not a magic bullet it just iterates over the array. Try solving it with Filter and then translate that.

@HassanM - i have tried as you are saying and per me it should give result but is not -


function whatIsInAName(collection, source) {
  // What's in a name?
  var arr = [];
  
  for(var key in collection){
if(collection[key] != undefined){
for(var key in source){
if(Collection[i][key] === Source[key]){
arr.push(collection[i]);
}
}
}
}
console.log(arr);
  // Only change code above this line
  return arr;
}

whatIsInAName([{ "a": 1, "b": 2 }, { "a": 1 }, { "a": 1, "b": 2, "c": 2 }], { "a": 1, "b": 2 });

So what i am doing is creating a collection of keys of both collection and source and then trying to compare if its not undefined still its now saying collection is not defined …where i am wrong can you please suggest

Regards

@HassanM @honmanyau @JohnL3 - I am trying this code -


function whatIsInAName(collection, source) {
  // What's in a name?
  var arr = [];
  for(var key in collection){
  console.log(collection[key]);
  }
  
  console.log(source);
  // Only change code above this line
  return arr;
}

whatIsInAName([{ "a": 1, "b": 2 }, { "a": 1 }, { "a": 1, "b": 2, "c": 2 }], { "a": 1, "b": 2 });

Now this gives me all the objects inside collectoin and the object source, why is there no function in javascript to check something like -

collection.contains(objects of source);

Like we have with strings etc …

Regards

//You need something more like:
for(var key in Object.keys(source)){
     for(var obj in collection){
          //Check if obj has the property with name key and then 
         //that the value of both source and obj match for the same key.
     }
}

I failed to mention something clearly earlier, which is that in JavaScript there are two ways to access a property, Dot notation and Bracket notation. Have a look at this link [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors](http://JavaScript Property_Accessors)

Have a look at this and see if it helps … mess around with it and then maybe put the objects into arrays and practice with them

1 Like

@JohnL3 - thanks for the code, however at line 17 i am unable to understand as to how -

if(objA[testKey] === test[testKey])

where in the task case an array of [“a”,“b”] can be compared here, i tried to use the logic till this point and came up with the below code , i am now getting 2 condition satisfied , but where there are more then 2 key-value pair in source its not working


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

 
 console.log(arr);
  // Only change code above this line
  return arr;
}

whatIsInAName([{ "a": 1, "b": 2 }, { "a": 1 }, { "a": 1, "b": 2, "c": 2 }], { "a": 1, "b": 2 });

Thanks again

 for(var i = 0; i < collection.length; i ++){
 if( collection[i].hasOwnProperty(testkey[0])){
 
 if(collection[i][testkey[0]] === source[testkey[0]]){
arr.push(collection[i]);
 }
 }
 }

Your getting closer … look at what i changed to what you supplied … testKey to testkey[0] …
testKey is array of keys … as my example had only one key i just used testKey … but if more than one key you have to use testKey[0] etc … change your above code and use testKey[0] … then use testKey[1] and see your results
you will then realize you need one more step … eg you need to loop through testKey as well as loop through collection so instead of having testKey[0] you can have testKey[x] …
edit looked at my solution and realize still more to be done but if you get this done can worry about that then