it-swarm.com.de

Der beste Weg, um die Kreuzung von Schlüsseln zweier Objekte zu erhalten?

Ich habe zwei Objektliterale so:

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
}

Ich möchte die Schnittmenge der Schlüssel ermitteln, die diese beiden Objektliterale wie folgt haben:

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

Ich kann natürlich eine Schleife machen und sehen, ob ein Schlüssel mit demselben Namen in dem anderen Objekt vorhanden ist, aber ich frage mich, ob dies ein guter Fall für eine funktionale Programmierung wäre und die Verwendung von Karten/Filtern/Verwenden verringern. Ich selbst habe nicht so viel funktionale Programmierung gemacht, aber ich habe das Gefühl, dass es eine saubere und clevere Lösung für dieses Problem geben könnte.

19
Piwwoli

Eine Lösung ohne 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>');

Zweiter Versuch mit 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

Die gegebenen Antworten sind nett und erstaunlich, aber es könnte ein Problem in void 's answer geben und das ist: "Was ist, wenn einer der Eigenschaftswerte absichtlich auf undefined gesetzt ist. "

Nina 's Antwort ist gut (wirklich fantastisch), aber da wir uns im JavaScript-Bereich von morgen befinden, denke ich, dass meine nicht zu schlecht sein wird:

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


Aktualisieren

onalbi erwähnte einige Performanceprobleme in Kommentaren, die rational sind, und daher scheint der folgende Code der bessere Weg zu sein, um das Problem zu lösen: 

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

Das Verfahren, das ich vorschlagen werde, ist:

  1. Rufen Sie die array der Schlüssel mit Object.keys() für eines der Objekte ab.
  2. Suchen Sie den Schnittpunkt des Arrays mit .filter und prüfen Sie, ob das zweite Objekt einen Schlüssel enthält, der mit dem ersten Array übereinstimmt.

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

Rekursive Funktion

Dies ist eine andere Lösung, vielleicht helfen Sie Ihnen. Ich habe eine rekursive Funktion verwendet, um zwei Objekte abzufangen. Der Vorteil dieser Lösung besteht darin, dass Sie sich nicht um Attribute kümmern müssen, die gleichzeitig Objekte sind. 

In diesem Fall fangen die Funktionen Attribute ab, die in beiden Objekten vorhanden sind, und weisen den Wert von 'objSource' als endgültigen Wert des Attributs intercepeted auf.

{
        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

Hier ist ein einfacher Eintrag, der sehr funktional ist, eine beliebige Anzahl von Objekten verarbeitet und die Werte der übereinstimmenden Schlüssel des ersten übergebenen Objekts zurückgibt.

Dieses Verhalten ähnelt dem von array_intersect_key () in PHP falls jemand danach sucht.

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

Hier zur besseren Erklärung und Kommentierung erweitert

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

Es ist wichtig zu beachten, dass diese Lösung nur für Zeichenfolgenschlüssel funktioniert. Symbolschlüssel werden ignoriert und das endgültige Objekt enthält keine. Es könnte jedoch auch eine ähnliche Funktion zum Vergleichen von Symbolschnittstellen geschrieben werden.

0
kyrandita