web-dev-qa-db-fra.com

Le meilleur moyen d'obtenir l'intersection des clés de deux objets?

J'ai deux objets littéraux comme suit:

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
}

Je veux obtenir l'intersection des clés que ces deux littéraux d'objet ont comme suit:

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

Je peux évidemment faire une boucle et voir si une clé du même nom existe dans l'autre objet, mais je me demande si ce serait un bon cas pour une programmation fonctionnelle et une utilisation de map/filter/réduire? Je n'ai moi-même pas fait beaucoup de programmation fonctionnelle, mais j'ai le sentiment qu'il pourrait exister une solution propre et intelligente à ce problème.

19
Piwwoli

Une solution sans 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>');

Deuxième tentative avec 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>');

24
Nina Scholz

Les réponses fournies sont agréables et étonnantes, mais il pourrait y avoir un problème dans void 's answer et c’est: "Et si l’une des valeurs de propriété définie intentionnellement sur undefined."

Nina 's answer est bon (vraiment fantastique) mais comme nous sommes au bord de demain de JavaScript, je pense que le mien ne sera pas trop mauvais:

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 => k in o2)
}

document.write('<pre>' + JSON.stringify(intersect(a, b)) + '</pre>');


Mettre à jour

onalbi a mentionné un problème de performance dans les commentaires qui est rationnel et par conséquent, le code ci-dessous semble être un meilleur moyen de gérer le problème: 

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

document.write('<pre>' + JSON.stringify(intersect(a, b)) + '</pre>');

14
Morteza Tourani

La procédure que je vais suggérer est la suivante:

  1. Obtenez la array de clés en utilisant Object.keys() pour l'un des objets.
  2. Recherchez l'intersection du tableau à l'aide de .filter et vérifiez si le deuxième objet contient une clé correspondant au premier tableau.

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

4
void

Fonction récursive

Ceci est une autre solution, peut-être vous aider. J'ai utilisé une fonction récursive pour intercepter deux objets. L'avantage de cette solution est que vous n'avez pas besoin de vous soucier des attributs qui sont des objets en même temps. 

Dans ce cas, la fonction intercepte les attributs existant dans les deux objets et attribue la valeur 'objSource' comme valeur finale de l'attribut intercepeted.

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

0
Amn