javascript 获得两个对象的关键帧交集的最佳方法?

7ajki6be  于 2023-03-06  发布在  Java
关注(0)|答案(6)|浏览(151)

我有两个对象常量,如下所示:

var firstObject =
{
    x: 0,
    y: 1,
    z: 2,

    a: 10,
    b: 20,
    e: 30
}

var secondObject =
{
    x: 0,
    y: 1,
    z: 2,

    a: 10,
    c: 20,
    d: 30
}

我想得到这两个对象常量的键的交集,如下所示:

var intersectionKeys  = ['x', 'y', 'z', 'a']

显然我可以循环看看另一个对象中是否存在同名的键,但是我想知道这是否是函数式编程和map / filter / reduce使用的一个好例子?我自己没有做过那么多函数式编程,但是我有一种感觉,对于这个问题可能存在一个干净而聪明的解决方案。

dgtucam1

dgtucam11#

没有indexOf的解决方案。

var firstObject = { x: 0, y: 1, z: 2, a: 10, b: 20, e: 30 },
    secondObject = { x: 0, y: 1, z: 2, a: 10, c: 20, d: 30 };

function intersection(o1, o2) {
    return Object.keys(o1).concat(Object.keys(o2)).sort().reduce(function (r, a, i, aa) {
        if (i && aa[i - 1] === a) {
            r.push(a);
        }
        return r;
    }, []);
}

document.write('<pre>' + JSON.stringify(intersection(firstObject, secondObject), 0, 4) + '</pre>');

时间复杂度O(n)

var firstObject = { x: 0, y: 1, z: 2, a: 10, b: 20, e: 30 },
    secondObject = { x: 0, y: 1, z: 2, a: 10, c: 20, d: 30 };

function intersection(o1, o2) {
    return Object.keys(o1).filter({}.hasOwnProperty.bind(o2));
}

document.write('<pre>' + JSON.stringify(intersection(firstObject, secondObject), 0, 4) + '</pre>');
f0ofjuux

f0ofjuux2#

给出的答案很好,令人惊讶,但可能有一个问题,在voidanswer,这是:"* 如果其中一个属性值有意设置为undefined,该怎么办。*"
Ninaanswer很好(真的很棒),但由于我们处于有趣JavaScript的时代,我认为我的不会太差:

var a = { x: undefined, y: 1, z: 2, a: 10, b: 20, e: 30 }
var b = { x: 0, y: 1, z: 2, a: 10, c: 20, d: 30 }

function intersect(o1, o2){
    return Object.keys(o1).filter(k => Object.hasOwn(o2, k))
}

console.log(intersect(a, b))

更新

onalbi在注解中提到了一些性能问题,这是合理的,因此下面的代码似乎是处理该问题的更好方法:

var a = { x: undefined, y: 1, z: 2, a: 10, b: 20, e: 30};
var b = { x: 0, y: 1, z: 2, a: 10, c: 20, d: 30};

function intersect(o1, o2) {

  const [k1, k2] = [Object.keys(o1), Object.keys(o2)];
  const [first, next] = k1.length > k2.length ? [k2, o1] : [k1, o2];
  return first.filter(k => k in next);
}

console.log(intersect(a, b))
niknxzdl

niknxzdl3#

我建议的程序是:
1.对于其中一个对象,使用Object.keys()获取键的array
1.使用.filter查找数组的交集,并检查第二个对象是否包含与第一个数组匹配的键。

var firstObject = {
  x: 0,
  y: 1,
  z: 2,

  a: 10,
  b: 20,
  e: 30
}

var secondObject = {
  x: 0,
  y: 1,
  z: 2,

  a: 10,
  c: 20,
  d: 30
}

function getIntKeys(obj1, obj2){

    var k1 = Object.keys(obj1);
    return k1.filter(function(x){
        return obj2[x] !== undefined;
    });
  
}

alert(getIntKeys(firstObject, secondObject));
lnxxn5zx

lnxxn5zx4#

递归函数

这是另一个解决方案,可能对你有帮助。我用了一个递归函数来截取两个对象。这个解决方案的优点是你不需要担心属性同时是对象。
在这种情况下,函数拦截两个对象中存在的属性,并分配“objSource”的值,就像拦截的属性的最终值一样。

{
        function interceptObjects(objSource, objInterface) {
            let newObj = {};
            for (const key in objSource) {
                if (objInterface.hasOwnProperty(key)) {
                    // in javascript an array is a object too.
                    if (objSource[key] instanceof Object && !Array.isArray(objSource[key]) && objInterface[key] instanceof Object && !Array.isArray(objInterface[key])) {
                        newObj[key] = {};
                        newObj[key] = interceptObjects(objSource[key], objInterface[key])
                    } else {
                        newObj[key] = objSource[key];
                    }

                }
            }
            return newObj;
        }
        
        
        // FOR TESTING


    let objSource = {
            attr1: '',
            attr2: 2,
            attr3: [],
            attr4: {
                attr41: 'lol',
                attr42: 12,
                attr43: 15,
                attr45: [1, 4],
            },
            attr5: [2, 3, 4],
        };


        let objInterface = {
            attr1: null,
            attr4: {
                attr41: null,
                attr42: 12,
                attr45: [1],
            },
            attr5: [],
            attr6: null,
        };


        console.log(this.interceptObjects(objSource, objInterface));
    }
yr9zkbsy

yr9zkbsy5#

下面是一个简单的条目,功能非常强大,可以处理任意数量的对象,并从传递的第一个对象返回匹配键的值。
这个行为类似于PHP中的array_intersect_key(),以防有人搜索它。

function intersectKeys(first, ...rest) {
    const restKeys = rest.map(o => Object.keys(o));
    return Object.fromEntries(Object.entries(first).filter(entry => restKeys.every(rk => rk.includes(entry[0]))));
}

在此扩展以获得更好的解释和注解

function intersectKeys(first, ...rest) {
    // extract the keys of the other objects first so that won't be done again for each check
    const restKeys = rest.map(o => Object.keys(o));
    // In my version I am returning the first objects values under the intersect keys
    return Object.fromEntries(
        // extract [key, value] sets for each key and filter them, Object.fromEntries() reverses this back into an object of the remaining fields after the filter
        Object.entries(first).filter(
            // make sure each of the other object key sets includes the current key, or filter it out
            entry => restKeys.every(
                rk => rk.includes(entry[0])
            )
        )
    );
    // to get JUST the keys as OP requested the second line would simplify down to this
    return Object.keys(first).filter(key => restKeys.every(rk => rk.includes(key)));
}

需要注意的是,这个解决方案只适用于字符串键,Symbol键将被忽略,最终的对象将不包含任何键。尽管可以编写一个类似的函数来比较Symbol的交集。

rqmkfv5c

rqmkfv5c6#

我知道这是一个老职位,但是,我想分享一个解决方案,我今天写的,我相信是高效和干净。

function intersectingKeys(...objects) {
  return objects
    .map((object) => Object.keys(object))
    .sort((a, b) => a.length - b.length)
    .reduce((a, b) => a.filter((key) => b.includes(key)));
}

该函数可以接收n个对象,并找到相交键。
这就是它的工作原理。
1.Map对象,创建键数组的数组。
1.按长度对数组排序,这将把最小的键数组放在第一位。
1.最后,通过根据下一个键列表过滤每个键列表来减少键数组。
我认为这个算法的聪明之处在于对键数组的预排序。通过从最小的键列表开始,我们比较键的工作就少了。
以下是常用语:

var firstObject = {
  x: 0,
  y: 1,
  z: 2,

  a: 10,
  b: 20,
  e: 30,
};

var secondObject = {
  x: 0,
  y: 1,
  z: 2,

  a: 10,
  c: 20,
  d: 30,
};

intersectingKeys(firstObject, secondObject);
// [ 'x', 'y', 'z', 'a' ]

相关问题