【问题标题】:Compare Object Arrays. Return matching Object keys & values比较对象数组。返回匹配的对象键和值
【发布时间】:2015-05-18 16:22:21
【问题描述】:

目标

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


示例 #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. 通常我会包含一些伪代码来突出我的思考过程。但是,我认为我已经掉进了兔子洞太深了。这里最好的方法是什么?我应该将对象展平成数组吗?对象有等效的 indexOf() 吗?
  2. 我听说您可以使用 Object.keys() 和 .hasOwnProperty() 来帮助完成此任务,但无法理解这两种方法如何协同工作来解决此问题。

【问题讨论】:

  • 那么您的困难在于如何检索source 中指定的密钥?
  • Lodash 来救援! lodash.com/docs#filter
  • @TedHopp 是的 - 我的困难是检索数组中的嵌套键和值,然后将它们与另一个对象数组进行比较
  • @Amit 不幸的是,这是在线学习课程的一部分,我无法导入自己的库:(
  • 您可能会发现getOwnPropertyNames() 函数很有用。

标签: javascript arrays object


【解决方案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];
      });
   });
}

【讨论】:

  • 它不适用于嵌套对象。看到这个 jsfiddle jsfiddle.net/jigardafda/54Ls1ewb/1
  • 是的。虽然这不是要求的一部分。该解决方案可以扩展以进行深度比较,但会更复杂。
【解决方案2】:

-> 解决方案 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>

-> 解决方案 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 实现与 jasmine 测试

【讨论】:

  • 不幸的是,我的问题是在线课程的一部分,我无法导入自己的库:(
  • 您可以在 lodash 库中检查 where 的实现。见github.com/lodash/lodash/blob/master/lodash.js#L7272
  • @jad-panda 你看过你提供的链接了吗?你基本上是在把读者送进兔子洞。
  • @jad-panda - 我想你做得很好(虽然不打算验证:-),但请注意最初的问题是什么......你的解决方案可能是一个极端的矫枉过正。当有人寻找这种复杂性时,最好使用外部库。
  • @Amit 解决方案并不过分,它只有 30 行代码。剩下的代码是测试。仅用于验证 where 是否正常工作。
猜你喜欢
  • 1970-01-01
  • 2020-09-26
  • 1970-01-01
  • 1970-01-01
  • 2022-01-02
  • 1970-01-01
  • 1970-01-01
  • 2021-02-04
  • 1970-01-01
相关资源
最近更新 更多