如何查找JavaScript对象之间的公共属性

如何查找JavaScript对象之间的公共属性,javascript,node.js,lodash,Javascript,Node.js,Lodash,查找对象数组的公共/不同属性的最佳/最有效方法是什么 我需要确定存在于所有对象中且具有相同值(公共值)的属性集。 最好我也希望得到一个具有所有其他属性的数组(diff) 我已经寻找了一个高效的库/函数来实现它。但是什么也没找到。所以我自己试过了 考虑这个JS对象数组: var objects = [{ id: '2j2w4f', color: 'red', height: 20, width: 40, owner: 'bob' }, { id: '

查找对象数组的公共/不同属性的最佳/最有效方法是什么

我需要确定存在于所有对象中且具有相同值(公共值)的属性集。 最好我也希望得到一个具有所有其他属性的数组(diff)

我已经寻找了一个高效的库/函数来实现它。但是什么也没找到。所以我自己试过了

考虑这个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
}];
我想将
颜色
(值为
红色
)确定为唯一的公共属性。 请注意,它们没有相同的属性集。例如,
所有者
不是公共财产

这是我自己解决问题的尝试(使用lodash):

我也尝试过mapReduce方法,但那似乎更糟

我仍然认为这似乎有点复杂/耗时,我将在1000-10000个或更多对象上执行此操作,每个对象具有20-50个属性

有什么建议吗?

编辑 对不起,我赶时间,没有足够的时间考虑。 事实上,没有必要这样做。我在想用二进制算法什么的

在这里,更新的代码没有排序。Console.time()给了我“3ms”。 我所做的与Bergi的解决方案类似,但是我没有收集所有明显的属性,而是搜索属性数量最少的元素。这减少了第二个循环的迭代次数

我的代码基于以下内容:

  • 如果对象X具有选定对象没有的属性,则它不是公共属性
  • 因此,选定对象具有所有公共属性+额外属性
  • 选定对象的属性最少,因此验证的迭代次数较少

//返回给定数组的公共属性。
函数getCommonProps(对象)
{
//具有最低属性的对象的存储变量。
var lowest={obj:null,nProperties:1000};
//搜索具有最低属性的对象。O(n)。
for(对象中的变量j)
{
var_nProp=Object.key(objects[j]).length;
如果(_nProp<最低性能)
最低={obj:objects[j],n属性:_nProp};
}
//保存公共属性的var。
var-retArr=[];
//属性最少的对象应包含公共属性。
用于(最低obj中的var i)
如果(isCommonProp(objects,i))重新定位推送(i);
回程回程;
}
//检查该道具是否存在于给定数组的所有对象中。
功能isCommonProp(arr,prop)
{
用于(arr中的var i)
{
if(arr[i][prop]==未定义)
返回false;
}
返回true;
}
time('getCommonProps()_perf');
log(getCommonProps(对象));
timeEnd('getCommonProps()_perf');

在您的解决方案中,有两件事情看起来是错误的:

  • 通过
    var common=objects[0]不复制对象,因此将损坏
    对象
  • 您可以检查obj中是否存在所有公共属性,还可以将obj的每个属性与当前公共属性进行比较。这似乎太过分了。起初没有意识到您也需要不同的
    属性
我会在两次循环中遍历数据。第一种方法是收集一个对象中的所有外观属性,第二种方法是测试它们是否常见:

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
    };
}

以下是我使用vanilla 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];
            }
        }
    }
}
函数公共差异属性(对象){
var common=JSON.parse(JSON.stringify(objects[0]);
var unmatchedProps={};
对于(变量i=1;i


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

以下是另一种使用和的方法:


你真的需要不同的属性吗?顺便说一句:修复了你对lodash不熟悉的问题,但在我看来,你是在迭代每个对象的属性,并将它们与第一个对象进行比较,这似乎是反向的。你应该只迭代第一个对象的属性,并将它们与其他对象进行比较对象(假设您只需要公共属性)。您还通过调用
delete common[key]来破坏
对象[0]
。我不会从第一个对象中删除,而是从一个空对象开始并添加公共属性。这也将避免@LeonidBeschastny@MattBurland是的,我需要一个不同的。但我也可以只检查一下普通的,一旦我需要知道一个给定的属性是否是不常见的只有在t的情况下,你的方法才有效
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
    };
}
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];
            }
        }
    }
}
_.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;
        }
    }, {});
}, {});