To find object whereabouts in array of objects

Viewed 69
function whatIsInAName(collection, source) {
  var result = [];
  var arr1 = Object.keys(source);
  console.log(arr1);

  for (var i = 0; i < collection.length; i++) {
    for (var j = 0; j < arr1.length; j++) {
      if (collection[i].hasOwnProperty(arr1[j]) === false) { //Check 1 if false go to next object  in collection
        break;
      } else if (collection[i].hasOwnProperty(arr1[j])) {
        console.log(source[arr1[j]], collection[i][arr1[j]])
        if (source[arr1[j]] !== collection[i][arr1[j]]) { //Check 2 if value is not equal break loop and goto next object in collection
          break;
        }
        continue; // if both check passes go for  next  property of source to check in object;
      }
      result.push(collection[i]); //if all values are present and checked in object push it in result array.
    }
  }
  return result;
}

console.log(whatIsInAName(
  [
    { a: 1, b: 2 },
    { a: 1 },
    { a: 1, b: 2, c: 2 }
  ], {
    a: 1,
    b: 2
  }
));

I couldn't figure out the problem in my logic. I try to debug it even but can't find what the hell is a problem with logic.The program is to make a function that looks through an array of objects (first argument) and returns an array of all objects that have matching property and value pairs (second argument) Kindly help me over, please.

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

should return

[{ "a": 1, "b": 2 }, { "a": 1, "b": 2, "c": 2 }].

and

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

should return

[{ "a": 1 }, { "a": 1 }, { "a": 1, "b": 2 }].
5 Answers

Well you are complicating it too much with these two for loops, you can do it better using Array built-in methods.

This is how you can do it using .filter() and .some() methods:

function whatIsInAName(collection, source) {

    var result = [];
    var arr1 = Object.keys(source);
    console.log(arr1);

    result = collection.filter(function(obj){
          return !arr1.some(function(k){
              return !obj[k] || obj[k] !== source[k];
          });
    });
    return result;
    }

    console.log(whatIsInAName([{ a: 1, b: 2 }, { a: 1 }, { a: 1, b: 2, c: 2 }], { a: 1, b: 2 }));

I think you are over complicating things. A simple .filter() will do. Inside that .filter() you can check to see if every value for every key in source matches with the corresponding key in collection by using the handy, built-in .every() method.

function whatIsInAName(collection, source) {
  var sourceKeys = Object.keys(source);
  return collection.filter(function (coll) {
    // if you want to return only exact matches, just add the test to make sure same # of keys, and all keys match w/ values.
    // (Object.keys(coll).length === sourceKeys.length) && sourceKeys.every(...)
    return sourceKeys.every(function (key) {
      return coll[key] === source[key];
    });
  });
}

console.log(whatIsInAName(
  [
    { a: 1, b: 2 },
    { a: 1 },
    { a: 1, b: 2, c: 2 }
  ], {
    a: 1,
    b: 2
  }
));

Alternatively, with ES6 Syntax:

function whatIsInAName(collection, source) {
  return collection.filter(coll => Object.keys(source).every(key => coll[key] === source[key]));
}

console.log(whatIsInAName(
  [
    { a: 1, b: 2 },
    { a: 1 },
    { a: 1, b: 2, c: 2 }
  ], {
    a: 1,
    b: 2
  }
));

Problem with your code :

What you are doing currently is that if all the if statements pass, and loops do not break anywhere, you put continue again at the last item of arr1. So, it goes to check next iteration, does not find it, and goes to next iteration in the collection loop. While doing this, it does not push any item to result.

Solution:

In your code: You should use continue like this.

if(j !==(arr1.length - 1)) 
  continue; 

This gives your code an opportunity to push item to result array.

Try this function

function whatIsInAName(arr, sources){
  return arr.filter((item) => {
    for(source in sources){
        if(!item[source] || item[source] !== sources[source]){
            return false;
        }
    }
    return true;
  })    
}

Your issue is that you are hitting your continue instead of falling out of the loop. I updated your code here:

function whatIsInAName(collection, source) {
    var result = [];
    var arr1 = Object.keys(source);
    console.log(arr1);

    for (var i = 0; i < collection.length; i++) {
        for (var j = 0; j < arr1.length; j++) {
            if (!collection[i].hasOwnProperty(arr1[j])) { //Check 1 if false go to next object  in collection
                break;
            } else if (collection[i].hasOwnProperty(arr1[j])) {
                console.log(source[arr1[j]], collection[i][arr1[j]])
                if (source[arr1[j]] !== collection[i][arr1[j]]) { //Check 2 if value is not equal break loop and goto next object in collection
                  break;
                }else if(j < arr1.length - 1){
                    continue; // if both check passes go for  next  property of source to check in object;
                }

            }
            result.push(collection[i]); 
        }
    }
    return result;
}

console.log(whatIsInAName(
  [
    { a: 1, b: 2 },
    { a: 1 },
    { a: 1, b: 2, c: 2 }
  ], 
  {
    a: 1,
    b: 2
  }
)); // result is [Object {...}, Object {...}] which objects are {a: 1, b: 2}, {a: 1, b: 2, c: 2}
Related