如何findJavaScript对象之间的共同属性

什么是find对象数组的通用/不同属性的最好/最有效的方法。

我需要确定所有对象中存在的属性集合,并且都具有相同的值(常见)。 最好我也想获得一个具有所有其他属性(差异)的数组。

我已经寻找一个有效的库/function,可以做到这一点。 但没有find任何东西。 所以我尝试了我自己。

考虑这个JS对象的数组:

var objects = [{ id: '2j2w4f', color: 'red', height: 20, width: 40, owner: 'bob' }, { id: '2j2w3f', color: 'red', height: 20, width: 41, owner: 'bob' }, { id: '2j2w2f', color: 'red', height: 21, }, { id: '2j2w1f', color: 'red', height: 21, width: 44 }]; 

我想确定color (价值red )作为唯一的共同财产。 请注意,它们没有相同的一组属性。 如owner不是共同财产。

这是我自己试图解决它(使用lodash):

 function commonDifferentProperties(objects) { // initialize common as first object, and then remove non-common properties. var common = objects[0]; var different = []; var i, obj; // iterate through the rest (note: i === 0 is not supposed to be covered by this) for (i = objects.length - 1; i > 0; i--) { obj = objects[i]; // compare each property of obj with current common _.forOwn(obj, function (value, key) { // if property not in current common it must be different if (_.isUndefined(common[key])) { if (!_.contains(different, key)) { different.push(key); } } else if (common[key] !== value) { // remove property from common if value is not the same delete common[key]; different.push(key); } }); // check that all properties of common is present in obj, if not, remove from common. _.forOwn(common, function (value, key) { if (_.isUndefined(obj[key])) { delete common[key]; different.push(key); } }); } return { common: common, different: different }; } 

js摆脱这个例子

我也尝试过mapReduce方法,但看起来更糟糕。

我仍然认为这看起来有些复杂/耗时,而且我会在1000-10000个物体或更多物体上做这个,每个物体有20-50个物体。

有什么build议么?

在解决scheme中有两件事看起来是错误的:

  • 通过var common = objects[0]; 你不要复制对象,所以你会破坏objects
  • 你们都检查obj中是否存在common的所有属性 ,还要比较obj的每个属性和当前的common属性 这似乎是一次太多。 一开始还没有意识到你需要different属性。

我会循环两遍的数据。 首先,你收集一个对象的所有明显的属性,在第二个testing它们是否共同:

 function commonDifferentProperties(objects) { var common = _.reduce(objects, function(acc, obj) { for (var p in obj) acc[p] = obj[p]; return acc; }, {}); var different = _.reduce(objects, function(acc, obj) { for (var p in common) if (common[p] !== obj[p]) { delete common[p]; acc.push(p); } return acc; }, []); return { common: common, different: different }; } 

以下是我使用的只是香草JS:

 function commonDifferentProperties(objects) { var common = JSON.parse(JSON.stringify(objects[0])); var unmatchedProps = {}; for (var i = 1; i < objects.length; i++) { for (var prop in objects[i]) { checkProps(objects[i],common,prop); } for (var commProp in common) { checkProps(common,objects[i],commProp); } } console.log(common); // this is all the matched key/value pairs console.log(unmatchedProps); // this is all the unmatched keys return { common: common, different: unmatchedProps }; function checkProps(source, target, prop) { if (source.hasOwnProperty(prop)) { var val = source[prop]; if (!target.hasOwnProperty(prop) || target[prop] !== val) { unmatchedProps[prop] = true; // note: you could extend this to store values, or number of times you found this key, or whatever delete common[prop]; } } } } 

http://jsfiddle.net/TwbPA/

所以我复制第一个对象,并使用它来跟踪常见的键和值。 然后我遍历数组中的所有其他对象,首先查看通用对象中的所有键/值,并与当前对象进行比较,如果它们不在当前对象中,则从公共对象中删除任何缺less的属性,然后执行捕获当前对象中不属于公共(或者在当前,但是具有错误值)的任何属性的相反。

编辑

对不起,我很匆忙,没有足够的时间去思考。 事实上,没有必要进行sorting。 我正在考虑使用二进制algorithm或什么的..

在这里,更新的代码没有sorting。 Console.time()给了我'3ms'。 我正在做类似于Bergi的解决scheme,但不是收集所有的显示属性,而是search具有最less数量属性的元素。 这减less了第二个循环的迭代次数。

我已经基于以下代码:

  • 如果对象X具有所选对象不具有的属性,则它不是一个公共属性!
  • 因此,选定的对象具有所有常见的属性+额外的。
  • 所选对象具有最less的属性,因此validation的迭代次数较less。

http://jsfiddle.net/kychan/cF3ne/1/

 // returns the common properties of given array. function getCommonProps(objects) { // storage var for object with lowest properties. var lowest = {obj:null, nProperties:1000}; // search for the object with lowest properties. O(n). for (var j in objects) { var _nProp = Object.keys(objects[j]).length; if (_nProp < lowest.nProperties) lowest = {obj:objects[j], nProperties:_nProp}; } // var that holds the common properties. var retArr = []; // The object with the fewest properties should contain common properties. for (var i in lowest.obj) if (isCommonProp(objects, i)) retArr.push(i); return retArr; } // Checks if the prop exists in all objects of given array. function isCommonProp(arr, prop) { for (var i in arr) { if (arr[i][prop]===undefined) return false; } return true; } console.time('getCommonProps()_perf'); console.log(getCommonProps(objects)); console.timeEnd('getCommonProps()_perf'); 

下面是使用reduce()和transform()的另一种方法:

 _.reduce(objects, function(result, item) { if (_.isEmpty(result)) { return _.assign({}, item); } return _.transform(item, function(common, value, key) { if (result[key] === value) { common[key] = value; } }, {}); }, {});