比较对象数组。返回匹配对象键&值

时间:2015-05-18 16:22:22

标签: javascript arrays object

目的

创建一个查看列表(集合)的函数,并返回具有等效属性值(源)的所有对象的数组。

示例#1

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

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

        { last: 'Capulet' });

预期输出#1

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

示例#2

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

     { 'a': 1 }), 

预期输出#2

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

问题

  1. 通常我会加入一些Psuedo代码来突出我的思维过程。但是,我想我已经陷入了兔子洞的深处。这里最好的方法是什么?我应该将对象展平成阵列吗?对象是否有等效的indexOf()?
  2. 我听说你可以使用Object.keys()和.hasOwnProperty()来帮助实现这一目标,但无法理解这两种方法如何协同解决这个问题。

2 个答案:

答案 0 :(得分:1)

由于您无法使用外部库,因此这是一种简单的方法来满足您的需求:

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

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

答案 1 :(得分:0)

<强> - &GT;解决方案1:使用Lodash Where

对于此类问题,您可以使用Lodash实用程序库。

Lodash已经拥有你需要的where功能。

见下面的例子。

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>

<强> - &GT;解决方案2:自定义Where实施

此实现适用于字符串,单个对象,一个级别对象和多个级别对象

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使用字符串,单个对象,一个级别对象和多个级别对象测试where

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>

更新:通过茉莉花测试添加了自定义where实施