检查一个对象数组中是否有任何一个对象包含另一个对象中的所有键/值对。

5
我正试图编写一个函数,该函数查找对象数组(第一个参数)并返回包含给定对象(第二个参数)的所有键/值对的对象数组。
我的代码仅在 source 对象(第二个参数)包含一个键/值对时起作用。当 source 对象有两个或更多的键/值对时,结果不如预期。
如何处理 source 对象中超过一个键/值对的情况?
function findObjects(collection, source) {
  var result = [];

  for (i=0; i<collection.length; i++) {
    for (var prop in source) {
      if (collection[i].hasOwnProperty(prop) && collection[i][prop] == source[prop]) {
        console.log('Collection\'s object ' + [i] + ' contains the source\'s key:value pair ' + prop + ': ' + source[prop] + '!');
        result.push(collection[i]);
      } else {
        console.log('fail');
      }
    }
  }

  console.log('The resulting array is: ' + result);
  return result;
}

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

// only the first object should be returned since it contains both "a":1 and "b":2
3个回答

3
你可以使用一些数组方法,比如Array#map

map()方法会在调用数组的每个元素上执行提供的函数,并返回一个新的数组,其结果是该函数的返回值。

并且使用Array#every

every()方法测试数组中是否所有元素都通过了由提供的函数实现的测试。

还要使用Object.keys获取源属性。 Object.keys()方法返回一个由指定对象的所有可枚举属性组成的数组,数组中属性名的排列顺序与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环会枚举原型链上的属性)。

function findObjects(collection, source) {
    var keys = Object.keys(source);          // get all properties of source
    return collection.filter(function (c) {  // filter collection
        return keys.every(function (k) {     // check every key
            return c[k] === source[k];       // compare value of collection and source
        });
    });
}

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

ES6语法中相同的写法(阅读更多:箭头函数

Basically this style is a short writing of

function (x) { return y; }

became

          x =>        y

function findObjects(collection, source) {
    const keys = Object.keys(source);
    return collection.filter(c => keys.every(k => c[k] === source[k]));
}

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


在你的第一次回复中,你有三个 return 语句,我不明白正在发生什么。如果你有时间,能否解释一下你的答案是怎么工作的?即,为什么它可以运行? - Brian Zelip
你的第一次回复中,(c)(k) 分别从哪里传递过来的? (感谢您的有用补充意见。) - Brian Zelip
1
ck是参数。 - Nina Scholz
那些参数是如何被满足的呢?是因为collection数组只有可枚举属性的对象,而source对象只有属性作为可枚举属性,所以JavaScript通过排除法知道要传递什么参数,因为没有其他可以作为参数传递的东西吗?编辑 因为c代表collection中的每个对象,k代表source中的每个属性,对吗? - Brian Zelip
1
右侧的 ccollection 的一个元素,而 ksource 的键(即 keys 的元素)。无论是 ES5 还是 ES6 的两个部分都完全相同。 - Nina Scholz

1
function findObjects(collection, source) {
    var result = [];

    for (i=0; i<collection.length; i++) {
        var matches = true;
        for (var prop in source) {
            if (!collection[i].hasOwnProperty(prop) || collection[i][prop] !== source[prop]) {
                matches = false;
                break;
            }
        }
        if (matches) {
            result.push(collection[i]);
        }
    }
    return result;
}

基本上,你需要检查所有属性并确保它们匹配,然后才将其添加到你的result数组中。

嘿!Jashaszun是第一个提供可行解决方案的人。(谢谢!)我还测试了RomanPerekhrest和Nina Scholz的回答,这两个也都有效。我很感激有机会从这三种不同的方法中学习。 - Brian Zelip
自由编程营的朋友们,大家好! - Brian Zelip

1

使用 Object.keysArray.forEachArray.some 函数的解决方案:

function findObjects(arr, source) {
    var keys = Object.keys(source), result = [];
    arr.forEach(function(v){
        !keys.some((k) => source[k] !== v[k]) && result.push(v);
    });

    return result;
}

console.log(findObjects([{ "a": 1, "b": 2 }, { "a": 1 }, { "b": 2, "c": 2 }], { "a": 1, "b": 2 }));
// it will output [{"a":1,"b":2}]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接