简体   繁体   中英

Compare Object Arrays. Return matching Object keys & values

OBJECTIVE

Make a function that looks through a list (collection) and returns an array of all objects that have equivalent property values (source).


EXAMPLE #1

    function where(collection, source) {
      var arr = [];
      return arr;
    }

    where([
        { first: 'Romeo', last: 'Montague' }, 
        { first: 'Mercutio', last: null }, 
        { first: 'Tybalt', last: 'Capulet' }], 

        { last: 'Capulet' });

EXPECTED OUTPUT #1

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

EXAMPLE #2

where(
    [{ 'a': 1 }, 
     { 'a': 1 },  
     { 'a': 1, 'b': 2 }], 

     { 'a': 1 }), 

EXPECTED OUTPUT #2

[{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }]

QUESTIONS

  1. Typically I include some Psuedo-code to highlight my thought process. However, I think I've fallen too deep into the rabbit hole. What is the best approach here? Should I flatten the objects into arrays? Is there an equivalent indexOf() for objects?
  2. I've heard you can use Object.keys() and .hasOwnProperty() to help accomplish this, but cannot comprehend how these two methods would work together to tackle this problem.

Since you can't use external libraries, here's a simple way to do what you need:

function where(collection, source) {
   var keys = Object.keys(source);

   return collection.filter(function (item) {
      return keys.every(function (key) {
         return source[key] == item[key];
      });
   });
}

-> Solution 1: Using Lodash Where

For this kind of problems, you can use Lodash utility library.

Lodash already has where function which you need.

see the below example.

 var out = _.where([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' }); document.getElementById('out').innerHTML = JSON.stringify(out); var out2 = _.where( [{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }], { 'a': 1 }); document.getElementById('out2').innerHTML = JSON.stringify(out2); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.8.0/lodash.js"></script> <div id="out"></div> <hr/> <div id="out2"></div> 


-> Solution 2: Custom Where Implementation

This implementation works with strings, single object , one level object and multilevel objects .

function typeOf(o) {
  return Object.prototype.toString.call(o).split(' ')[1].split(']')[0].toLowerCase();
}

function isUndefined(o) {
  return typeOf(o) === 'undefined';
}

function where(collection, source) {
  var checkArr = [];

  if (typeOf(collection) === 'object') {
    checkArr = [collection];
  } else if (typeOf(collection) === 'array') {
    checkArr = collection;
  }

  function isObjectSemiSame(obj, source, u) {
    return Object.keys(source).every(function(key) {
      if (isUndefined(obj) || isUndefined(obj[key])) {
        return;
      }
      if (typeOf(source[key]) === 'object' || typeOf(source[key]) === 'array') {
        return isObjectSemiSame(obj[key], source[key]);
      }
      return source[key] === obj[key];
    });
  }

  return checkArr.filter(function(item) {
    return isObjectSemiSame(item, source);
  });
}

Jasmine tests for testing where with strings, single object, one level object and multilevel objects.

 function typeOf(o) { return Object.prototype.toString.call(o).split(' ')[1].split(']')[0].toLowerCase(); } function isUndefined(o) { return typeOf(o) === 'undefined'; } function where(collection, source) { var checkArr = []; if (typeOf(collection) === 'object') { checkArr = [collection]; } else if (typeOf(collection) === 'array') { checkArr = collection; } function isObjectSemiSame(obj, source, u) { return Object.keys(source).every(function(key) { if (isUndefined(obj) || isUndefined(obj[key])) { return; } if (typeOf(source[key]) === 'object' || typeOf(source[key]) === 'array') { return isObjectSemiSame(obj[key], source[key]); } return source[key] === obj[key]; }); } return checkArr.filter(function(item) { return isObjectSemiSame(item, source); }); } describe('where method', function() { it('testing with strings', function() { var collection = [ "one", "two", "three" ]; var collection = [ "bamboo", "two", "bamboo", "link" ]; expect(where(collection, "two")).toEqual(["two"]); expect(where(collection, "bamboo")).toEqual(["bamboo", "bamboo"]); }); it('testing with one object', function() { var collection1 = { name: 'raju', age: 23, }; var collection2 = { name: 'Friko', age: 36, }; expect(where(collection1, { name: 'raju' })).toEqual([collection1]); expect(where(collection1, { name: 'Dump' })).toEqual([]); expect(where(collection2, { age: 36 })).toEqual([collection2]); expect(where(collection2, { car: 'audi' })).toEqual([]); }); it('testing with one level object', function() { var collection = [{ name: 'jack', age: 25 }, { name: 'missi', age: 23 }, { name: 'reddy', age: 46 }]; var source1 = { name: 'reddy' }; var source2 = { age: 25 }; expect(where(collection, source1)).toEqual([collection[2]]); expect(where(collection, source2)).toEqual([collection[0]]); }); it('testing with multilevel object', function() { var collection = [{ name: 'jack', age: 25, level1: { name: 'l1', level2: { name: 'l2', level3: { name: 'l3' } } } }, { name: 'missi', age: 23, level1: { name: 'l1' } }, { name: 'reddy', age: 46, feature: { flag: false } }]; var source1 = { level1: { name: 'l1' } }; var source2 = { level1: { name: 'l1', level2: { name: 'l2' } } }; var source3 = { feature: { flag: false } }; expect(where(collection, source1).length).toBe(2); expect(where(collection, source1)).toEqual(jasmine.arrayContaining([ collection[0], collection[1] ])); expect(where(collection, source2)).toEqual([collection[0]]); expect(where(collection, source3)).toEqual([collection[2]]); }); }); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.2.1/jasmine.min.js"></script> <link href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.2.1/jasmine.min.css" rel="stylesheet" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.2.1/jasmine-html.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.2.1/boot.min.js"></script> 

UPDATE: added custom where implementation with jasmine tests

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM