admin管理员组文章数量:1393091
What is the best/most efficient way to find the mon/different properties of an array of objects.
I need to identify the set of properties that exists in all objects and all have the same value(the mon). Preferably I would also like to get an array with all other properties (the diff).
I have searched for an efficient library/function that can do it. But didn't find anything. So I tried on my own.
Consider this array of JS objects:
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
}];
I would like to identify color
(with value red
) as the only mon property.
Note that they do not have the same set of properties. E.g. owner
is not a mon property.
This is my own attempt to solve it (using lodash):
function monDifferentProperties(objects) {
// initialize mon as first object, and then remove non-mon properties.
var mon = 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];
// pare each property of obj with current mon
_.forOwn(obj, function (value, key) {
// if property not in current mon it must be different
if (_.isUndefined(mon[key])) {
if (!_.contains(different, key)) {
different.push(key);
}
} else if (mon[key] !== value) { // remove property from mon if value is not the same
delete mon[key];
different.push(key);
}
});
// check that all properties of mon is present in obj, if not, remove from mon.
_.forOwn(mon, function (value, key) {
if (_.isUndefined(obj[key])) {
delete mon[key];
different.push(key);
}
});
}
return {
mon: mon,
different: different
};
}
jsFiddle with the example
I have also tried a mapReduce approach, but that seemed even worse.
I still think this seems a bit plex/time consuming, and I will do this on 1000-10000 objects or more with 20-50 properties each.
Any suggestions?
What is the best/most efficient way to find the mon/different properties of an array of objects.
I need to identify the set of properties that exists in all objects and all have the same value(the mon). Preferably I would also like to get an array with all other properties (the diff).
I have searched for an efficient library/function that can do it. But didn't find anything. So I tried on my own.
Consider this array of JS objects:
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
}];
I would like to identify color
(with value red
) as the only mon property.
Note that they do not have the same set of properties. E.g. owner
is not a mon property.
This is my own attempt to solve it (using lodash):
function monDifferentProperties(objects) {
// initialize mon as first object, and then remove non-mon properties.
var mon = 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];
// pare each property of obj with current mon
_.forOwn(obj, function (value, key) {
// if property not in current mon it must be different
if (_.isUndefined(mon[key])) {
if (!_.contains(different, key)) {
different.push(key);
}
} else if (mon[key] !== value) { // remove property from mon if value is not the same
delete mon[key];
different.push(key);
}
});
// check that all properties of mon is present in obj, if not, remove from mon.
_.forOwn(mon, function (value, key) {
if (_.isUndefined(obj[key])) {
delete mon[key];
different.push(key);
}
});
}
return {
mon: mon,
different: different
};
}
jsFiddle with the example
I have also tried a mapReduce approach, but that seemed even worse.
I still think this seems a bit plex/time consuming, and I will do this on 1000-10000 objects or more with 20-50 properties each.
Any suggestions?
Share Improve this question edited Apr 21, 2014 at 17:12 mikaelhm asked Apr 21, 2014 at 14:23 mikaelhmmikaelhm 953 silver badges8 bronze badges 7- Do you actually need the different properties too as in your fiddle? BTW: fixed your fiddle – Matt Burland Commented Apr 21, 2014 at 14:27
- Not familiar with lodash, but it looks to me like you are iterating over the properties of each object and paring them to the first object, which seems backwards. You should iterate over the properties of only the first object and pare them with each other object (assuming you only want the mon properties). – Matt Burland Commented Apr 21, 2014 at 14:30
-
4
You're also corrupting your
objects[0]
by callingdelete mon[key];
. – Leonid Beschastny Commented Apr 21, 2014 at 14:33 - Instead of deleting from the first object, I would start with an empty object and add mon properties. It will also avoid the problem mentioned by @LeonidBeschastny – Ingo Bürk Commented Apr 21, 2014 at 14:52
- @MattBurland Yes, I need the different one once somewhat. But I could also just check against the mon ones, once I need to know if a given property is not-mon. As I see it, you approach only works if they all have the same properties with different values. Lodash is a utility library – mikaelhm Commented Apr 21, 2014 at 16:25
4 Answers
Reset to default 1There are two things that are look wrong in your solution:
- By
var mon = objects[0];
you don't copy the object, so you're going to corrupt theobjects
You both check that all properties of mon is present in obj, but also pare each property of obj with current mon. That seems to be once too much.Didn't realize at first that you needed thedifferent
properties as well.
I'd loop over the data in two passes. In the first, you collect all apparent properties in one object, in the second you test whether they're mon or not:
function monDifferentProperties(objects) {
var mon = _.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 mon)
if (mon[p] !== obj[p]) {
delete mon[p];
acc.push(p);
}
return acc;
}, []);
return {
mon: mon,
different: different
};
}
Here's what I did using just vanilla JS:
function monDifferentProperties(objects) {
var mon = 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],mon,prop);
}
for (var mProp in mon) {
checkProps(mon,objects[i],mProp);
}
}
console.log(mon); // this is all the matched key/value pairs
console.log(unmatchedProps); // this is all the unmatched keys
return { mon: mon, 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 mon[prop];
}
}
}
}
http://jsfiddle/TwbPA/
So I copy the first object and use that to keep track of keys and values that are mon. Then I iterate through all the other objects in your array and first look through all the key/values in the mon object and pare to the current, deleting any missing properties from the mon object if they are not in the current one, then I do the reverse to catch any properties in the current object that aren't in the mon (or are in the current, but have the wrong value).
Edit
Sorry, i was in a hurry and didn't had enough time to think about it. Indeed, there's no need for a sort. I was thinking using a binary algorithm or something..
Here, the updated code without the sort. Console.time() gave me '3ms'. I'm doing similar to Bergi's solution, but instead of collecting all apparant properties i search for the element that has the fewest amount of properties. This reduces the amount of iterations on the second loop.
I've based the code on the following:
- if object X has a property the selected object doesn't have, then it isn't a mon property!
- Thus the selected object has all mon properties + extra's.
- The selected object has the fewest properties, thus the iterations of validating is less.
http://jsfiddle/kychan/cF3ne/1/
// returns the mon 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 mon properties.
var retArr = [];
// The object with the fewest properties should contain mon 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');
Here's another approach that uses reduce() and transform():
_.reduce(objects, function(result, item) {
if (_.isEmpty(result)) {
return _.assign({}, item);
}
return _.transform(item, function(mon, value, key) {
if (result[key] === value) {
mon[key] = value;
}
}, {});
}, {});
本文标签: nodejsHow to find common properties between JavaScript objectsStack Overflow
版权声明:本文标题:node.js - How to find common properties between JavaScript objects - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744720512a2621663.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论