webentwicklung-frage-antwort-db.com.de

Wie kann man zwei Objekte vergleichen und Schlüssel-Wert-Paare ihrer Unterschiede erhalten?

Ich habe zwei Objekte:

1)

{A: 10, B: 20, C: 30}

2)

{A: 10, B: 22, C: 30}

wie Sie sehen können: Es gibt fast die gleichen, außer eines: Schlüssel B Wert ist anders.

Wie komme ich in meine someNewArr Schlüsselwert-Differenzmenge?

wie someNewArr: {B: 22} (ich erhalte Werte vom zweiten Objekt)

ich benutze Angular, und ich meine so etwas wie:

    var compareTwoObjects = function(initialObj, editedObj) {
        var resultArr = [];
        angular.forEach(initialObj, function(firstObjEl, firstObjInd) {
            angular.forEach(editedObj, function(secondObjEl, secondObjInd) {
                if (firstObjEl.key === secondObjEl.key && firstObjEl.value !== secondObjEl.value){
                    resultArr.Push({firstObjEl.key: secondObjEl.value});
                }
            })
        });
    });
7
brabertaser19

rekursives Diff

Fast 3 Jahre später bin ich froh, eine erfrischende Antwort auf diese Frage zu geben.

Wir beginnen mit zwei unterschiedlichen Objekten

const x =
  { a: 1, b: 2, c: 3 }

const y =
  { a: 1, b: 3, d: 4 }

console.log (diff (x, y))
// => ???

Beide Objekte haben dieselbe Eigenschaft aname__. Die Eigenschaft bist nicht dieselbe. Nur xhat eine Eigenschaft cname__, und nur yhat eine Eigenschaft dname__. Also, was sollte ??? genau sein?

Aus der Sicht von diffkann die Beziehung zwischen unseren Eingabeobjekten aund bvöllig beliebig sein. Um mitzuteilen, welches Objekt zu einer Differenz beiträgt, weist diffDeskriptoren leftund rightzu.

console.log (diff (x, y))
// { b: { left: 2, right: 3 }, c: { left: 3 }, d: { right: 4 } }

In der Ausgabe oben können wir sehen

  • welche Eigenschaften sind unterschiedlich - bname__, cund dname__
  • welches Objekt hat den Unterschied beigetragen - leftund/oder rightname__
  • der "andere" Wert - zum Beispiel hat der linke bden Wert 2, der rechte bden Wert 3; oder der linke chat einen Wert von 3, der rechte chat einen Wert von undefined

Bevor wir mit der Implementierung dieser Funktion beginnen, untersuchen wir zunächst ein komplexeres Szenario mit tief verschachtelten Objekten

const x =
  { a: { b: { c: 1, d: 2, e: 3 } } }

const y =
  { a: { b: { c: 1, d: 3, f: 4 } } }

console.log (diff (x, y))
// { a: { b: { d: { left: 2, right: 3 }, e: { left: 3 }, f: { right: 4 } } } }

Wie wir oben sehen können, gibt diffeine Struktur zurück, die unseren Eingaben entspricht. Und schließlich erwarten wir, dass der diffvon zwei gleichen Objekten ein "leeres" Ergebnis zurückgibt

const x1 =
  { a: 1, b: { c: { d: 2 } } }

const x2 =
  { a: 1, b: { c: { d: 2 } } }

console.log (diff (x1, x2))
// {}

Oben beschreiben wir eine Funktion diffname__, die sich nicht um die angegebenen Eingabeobjekte kümmert. Das "linke" Objekt kann Schlüssel enthalten, die das "rechte" Objekt nicht enthält, und umgekehrt, dennoch müssen wir Änderungen von beiden Seiten erkennen. Ausgehend von einer hohen Ebene werden wir auf diese Weise das Problem angehen

const diff = (x = {}, y = {}) =>
  merge
    ( diff1 (x, y, "left")
    , diff1 (y, x, "right")
    ) 

diff1

Wir nehmen ein "einseitiges" Diff unter Verwendung von diff1, das als die "linke" Beziehung beschrieben wird, und wir nehmen ein weiteres einseitiges Diff mit den umgekehrten Eingabeobjekten, das als die "rechte" Beziehung beschrieben wird, dann mergename__, die beiden Ergebnisse zusammen

Unsere Arbeit gliedert sich für uns in Aufgaben, die jetzt einfacher zu erledigen sind. diff1 muss nur die Hälfte der notwendigen Änderungen erkennen und mergekombiniert einfach die Ergebnisse. Wir beginnen mit diff1

const empty =
  {}

const isObject = x =>
  Object (x) === x

const diff1 = (left = {}, right = {}, rel = "left") =>
  Object.entries (left)
    .map
      ( ([ k, v ]) =>
          isObject (v) && isObject (right[k])
            ? [ k, diff1 (v, right[k], rel) ]
            : right[k] !== v
              ? [ k, { [rel]: v } ]
              : [ k, empty ]
      )
    .reduce
      ( (acc, [ k, v ]) =>
          v === empty
            ? acc
            : { ...acc, [k]: v }
      , empty
      )

diff1 akzeptiert zwei Eingabeobjekte und einen Beziehungsdeskriptor, relname__. Dieser Deskriptor ist standardmäßig "left". Dies ist die Standardausrichtung des Vergleichs. Beachten Sie, dass diff1 nur die Hälfte des von uns benötigten Ergebnisses liefert. Das Umkehren der Argumente in einem zweiten Aufruf von diff1 liefert die andere Hälfte.

const x =
  { a: 1, b: 2, c: 3 }

const y =
  { a: 1, b: 3, d: 4 }

console.log (diff1 (x, y, "left"))
// { b: { left: 2 }, c: { left: 3 } }

console.log (diff1 (y, x, "right"))
// { b: { right: 3 }, d: { right: 4 } }

Erwähnenswert ist auch, dass die Beziehungsbezeichnungen "left" und "right" benutzerdefinierbar sind. Wenn Sie beispielsweise eine bekannte Beziehung zwischen den zu vergleichenden Objekten haben und in der Diff-Ausgabe aussagekräftigere Beschriftungen bereitstellen möchten ...

const customDiff = (original = {}, modified = {}) =>
  merge
    ( diff1 (x, y, "original")
    , diff1 (y, x, "modified")
    )

customDiff
    ( { Host: "localhost", port: 80 }
    , { Host: "127.0.0.1", port: 80 }
    )
// { Host: { original: 'localhost', modified: '127.0.0.1' } }

Im obigen Beispiel ist es möglicherweise einfacher, mit der Ausgabe in anderen Bereichen Ihres Programms zu arbeiten, da die Bezeichnungen originalund modifiedaussagekräftiger sind als leftund rightname__.

Zusammenführen

Alles, was bleibt, ist das Zusammenführen der beiden Halbdifferenzen zu einem vollständigen Ergebnis. Unsere Funktion mergefunktioniert auch generisch und akzeptiert zwei beliebige Objekte als Eingabe.

const x =
  { a: 1, b: 1, c: 1 }

const y =
  { b: 2, d: 2 }

console.log (merge (x, y))
// { a: 1, b: 2, c: 1, d: 2 }

Wenn jedes Objekt eine Eigenschaft enthält, deren Wert also ein Objekt ist, werden die verschachtelten Objekte von mergeebenfalls wiederholt und zusammengeführt.

const x =
  { a: { b: { c: 1, d: 1 } } }

const y =
  { a: { b: { c: 2, e: 2 } }, f: 2 }

console.log (merge (x, y))
// { a: { b: { c: 2, d: 1, e: 2 } }, f: 2 }

Unten kodieren wir unsere Absichten in mergename__

const merge = (left = {}, right = {}) =>
  Object.entries (right)
    .reduce
      ( (acc, [ k, v ]) =>
          isObject (v) && isObject (left [k])
            ? { ...acc, [k]: merge (left [k], v) }
            : { ...acc, [k]: v }
      , left
      )

Und das ist das ganze Kit und Caboodle! Erweitern Sie das folgende Code-Snippet, um eine Code-Demonstration in Ihrem eigenen Browser auszuführen

const empty =
  {}

const isObject = x =>
  Object (x) === x

const diff1 = (left = {}, right = {}, rel = "left") =>
  Object.entries (left)
    .map
      ( ([ k, v ]) =>
          isObject (v) && isObject (right[k])
            ? [ k, diff1 (v, right[k], rel) ]
            : right[k] !== v
              ? [ k, { [rel]: v } ]
              : [ k, empty ]
      )
    .reduce
      ( (acc, [ k, v ]) =>
          v === empty
            ? acc
            : { ...acc, [k]: v }
      , empty
      )

const merge = (left = {}, right = {}) =>
  Object.entries (right)
    .reduce
      ( (acc, [ k, v ]) =>
          isObject (v) && isObject (left [k])
            ? { ...acc, [k]: merge (left [k], v) }
            : { ...acc, [k]: v }
      , left
      )

const diff = (x = {}, y = {}) =>
  merge
    ( diff1 (x, y, "left")
    , diff1 (y, x, "right")
    )

const x =
  { a: { b: { c: 1, d: 2, e: 3 } } }

const y =
  { a: { b: { c: 1, d: 3, f: 4 } } }

console.log (diff (x, y))
// { a: { b: { d: { left: 2, right: 3 }, e: { left: 3 }, f: { right: 4 } } } }

console.log (diff (diff (x,y), diff (x,y)))
// {} 

Bemerkungen

Wenn wir auf unsere Funktion diffzurückblicken, möchte ich einen wichtigen Teil ihres Designs hervorheben. Ein guter Teil der Arbeit wird von der Funktion mergeerledigt, die völlig unabhängig von diffist, jedoch eine harte Nuss für sich allein. Da wir unsere Anliegen in einzelne Funktionen unterteilt haben, ist es jetzt einfach, sie in anderen Bereichen Ihres Programms wiederzuverwenden. Wo wir diffhaben wollten, haben wir es bekommen, und wir haben eine intuitive, tiefe mergename__-Funktionalität gratis bekommen.


extra: Unterstützung für Arrays

Unsere Funktion diffist sehr praktisch, da sie tief verschachtelte Objekte crawlen kann. Was aber, wenn eine unserer Objekteigenschaften ein Array ist? Es wäre schön, wenn wir Arrays mit derselben Technik unterscheiden könnten.

Für die Unterstützung dieser Funktion sind nicht unbedeutende Änderungen am obigen Code erforderlich. Der Großteil der Struktur und Argumentation bleibt jedoch gleich. Beispielsweise ist diffvollständig unverändert

// unchanged
const diff = (x = {}, y = {}) =>
  merge
    ( diff1 (x, y, "left")
    , diff1 (y, x, "right")
    )

Um Arrays in mergezu unterstützen, führen wir einen Mutation Helper mutein, der einem bestimmten Objekt, oname__, ein [ key, value ]-Paar zuweist. Arrays werden ebenfalls als Objekte betrachtet, sodass wir sowohl Arrays als auch Objekte mit derselben Funktion mutaktualisieren können

const mut = (o, [ k, v ]) =>
  (o [k] = v, o)

const merge = (left = {}, right = {}) =>
  Object.entries (right)
    .map
      ( ([ k, v ]) =>
          isObject (v) && isObject (left [k])
            ? [ k, merge (left [k], v) ]
            : [ k, v ]
      )
    .reduce (mut, left)

Shallow Merges funktionieren wie erwartet

const x =
  [ 1, 2, 3, 4, 5 ]

const y =
  [ 0, 0, 0 ]

const z =
  [ , , , , , 6 ]

console.log (merge (x, y))
// [ 0, 0, 0, 4, 5 ]

console.log (merge (y, z))
// [ 0, 0, 0, <2 empty items>, 6 ]

console.log (merge (x, z))
// [ 1, 2, 3, 4, 5, 6 ]

Und tief verschmilzt auch

const x =
  { a: [ { b: 1 }, { c: 1 } ] }

const y =
  { a: [ { d: 2 }, { c: 2 }, { e: 2 } ] }

console.log (merge (x, y))
// { a: [ { b: 1, d: 2 }, { c: 2 }, { e: 2 } ] }

Die Unterstützung von Arrays in diff1 ist erheblich anspruchsvoller

const diff1 = (left = {}, right = {}, rel = "left") =>
  Object.entries (left)
    .map
      ( ([ k, v ]) =>
          isObject (v) && isObject (right[k])
            ? [ k, diff1 (v, right[k], rel) ]
            : right[k] !== v
              ? [ k, { [rel]: v } ]
              : [ k, {} ]
      )
    .filter
      ( ([ k, v ]) =>
          Object.keys (v) .length !== 0
      )
    .reduce
      ( mut
      , isArray (left) && isArray (right) ? [] : {}
      )

Aber mit diesen Änderungen können wir jetzt Objekte, die Arrays enthalten, und sogar Arrays, die Objekte enthalten, gründlich vergleichen!

const x =
  { a: 1, b: [ { c: 1 }, { d: 1 }, { e: 1 } ] }

const y =
  { a: 1, b: [ { c: 2 }, { d: 1 }, 5, 6 ], z: 2 }

console.log (diff (x, y))
// { b:
//     [ { c: { left: 1, right: 2 } }
//     , <1 empty item>
//     , { left: { e: 1 }, right: 5 }
//     , { right: 6 }
//     ]
// , z: { right: 2 } 
// }

Da diff1 sein Verhalten basierend auf den Eingabetypen sorgfältig ändert, erhalten wir Array-Unterschiede kostenlos

const x =
  [ 1, 2, 3, 4 ]

const y =
  [ 1, 2, 9 ]

const z =
  [ 1, 2, 9 ]

console.log (diff (x, y))
// [ <2 empty items>, { left: 3, right: 9 }, { left: 4 } ]

console.log (diff (y, z))
// []

Führen Sie das vollständige Programm in Ihrem Browser aus

const isObject = x =>
  Object (x) === x

const isArray =
  Array.isArray

const mut = (o, [ k, v ]) =>
  (o [k] = v, o)

const diff1 = (left = {}, right = {}, rel = "left") =>
  Object.entries (left)
    .map
      ( ([ k, v ]) =>
          isObject (v) && isObject (right[k])
            ? [ k, diff1 (v, right[k], rel) ]
            : right[k] !== v
              ? [ k, { [rel]: v } ]
              : [ k, {} ]
      )
    .filter
      ( ([ k, v ]) =>
          Object.keys (v) .length !== 0
      )
    .reduce
      ( mut
      , isArray (left) && isArray (right) ? [] : {}
      )

const merge = (left = {}, right = {}) =>
  Object.entries (right)
    .map
      ( ([ k, v ]) =>
          isObject (v) && isObject (left [k])
            ? [ k, merge (left [k], v) ]
            : [ k, v ]
      )
    .reduce (mut, left)


const diff = (x = {}, y = {}) =>
  merge
    ( diff1 (x, y, "left")
    , diff1 (y, x, "right")
    )

const x =
  { a: 1, b: [ { c: 1 }, { d: 1 }, { e: 1 } ] }

const y =
  { a: 1, b: [ { c: 2 }, { d: 1 }, 5, 6 ], z: 2 }

console.log (diff (x, y))
// { b:
//     [ { c: { left: 1, right: 2 } }
//     , <1 empty item>
//     , { left: { e: 1 }, right: 5 }
//     , { right: 6 }
//     ]
// , z: { right: 2 } 
// }

flacher Unterschied

Die vorherige Version dieser Antwort enthielt eine Objektfunktion diffzum Vergleichen von Objekten mit denselben Schlüsseln und zum Vergleichen von Objekten mit unterschiedlichen Schlüsseln, aber keine der beiden Lösungen führte den Diff rekursiv für verschachtelte Objekte aus.

rekursive Vereinigung

In dieser verwandten F & A nehmen wir zwei Eingabeobjekte und berechnen einen rekursiven unionanstelle eines diffname__

16
user633183

Diese Lösung ist nicht in eckigen, aber es könnte helfen.

Es werden 2 Objekte mit einer beliebigen Anzahl von Schlüsseln benötigt, und sie müssen nicht dieselben Schlüssel enthalten.

** Ausgabe: ** The key:value pairs which are present in only one object and not the other and the key:value pairs which are present in both objects but the values are different.

var obj1 = {A: 10, B: 20, C: 30, E: 40};
var obj2 = {A: 11, B: 20, C: 30, D: 50};
var finalObject = {};

$( document ).ready(function() {
    var keysOfObj1 = Object.keys( obj1 );
    var keysOfObj2 = Object.keys( obj2 );

    var keys = [];
    keys = $( keysOfObj1 ).not( keysOfObj2 ).get(); // keys of first object not in second object

    for( var i=0;i<keys.length;i++ ) {
        finalObject[ keys[ i ] ] = obj1[ keys[ i ] ];
    }

    keys.length = 0; // reset the temp array

    keys = $( keysOfObj2 ).not( keysOfObj1 ).get(); // keys of second object not in first object

    for( var i=0;i<keys.length;i++ ) {
        finalObject[ keys[ i ] ] = obj2[ keys[ i ] ];
    }

    keys.length = 0; // reset the temp array again

    if( keysOfObj1.length != keysOfObj2.length ) {
        // case already handled above
    }

    for( var i in obj1 ) {
        if( obj1.hasOwnProperty( i ) ) {
            if( obj2.hasOwnProperty( i ) ) {
                if( obj1[ i ] != obj2[ i ] ) {
                    finalObject[ i ] = obj2[ i ];
                } else {
                    // the property has the same value in both objects, all is well...
                }
            } else {
                // case already handled above
            }
        } else {
            // case already handled above
        }
    }
    console.log( obj1 );
    console.log( obj2 );
    console.log( finalObject );

Ich hoffe es hilft.

0
web-nomad

Die Lösung ist ganz einfach,

Initialisieren Sie Ihr Array,

var resultArray = [];

blättern Sie dann durch die Schlüssel Ihres Objekts und verwenden Sie einen als Referenz. (Vorausgesetzt, die Objekte haben dieselben Schlüssel, aber Sie möchten Schlüssel mit unterschiedlichen Werten prüfen.)

und schließlich den einfachen Code ausführen

for(let key in obj){
    // console.log(key);
    if(obj[key]  !== this.profileObject[key] ){
      resultArray.Push(key);
    }
}

Und sammeln Sie Ihre Antwort am Ende

console.log(resultArray);
0
theProgrammer

Dadurch wird das Diff des ersten Arguments in Bezug auf das zweite Argument zurückgegeben. Ich benutze hier allerdings nicht angle.forEach.

var x = {
   a : 1,
   b:2,
  c :3,
  d:4
 }

var y = {
   a : 1,
   b:4,
  c :3,
  d : 5
 };


var diff = function(x,y){
  var target = {};   
  var diffProps = Object.keys(x).filter(function(i){
    if(x[i] !== y[i]){
      return true;
    }
    return false;
   }).map(function(j){
       var obj = {};
       obj[j] = x[j];
       target = Object.assign(target,obj)
  });
   return target;
};


console.log(diff(x,y));
0

Versuchen Sie dies

function getNewProperties(prevObj, newObj) {
  const prevObjProperties = Object.keys(prevObj);
  const newObjProperties = Object.keys(newObj);
  const newProperties = newObjProperties.filter(prop => prevObjProperties.indexOf(prop) === -1);
  return newProperties;
}
0
Debojyoti

Ich hoffe, dies wird dir helfen. Ich habe es mit der Funktion jQuery each gemacht.

var a = {A: 10, B: 20, C: 30};
var b = {A: 10, B: 22, C: 30};
var hasObj = false; //Declaring variable outside for onetime memory allocation.

$.each(b, function(keyOfB, valOfB) {

    hasObj = false;  //Assigning false for each parent loop

    $.each(a, function(keyOfA, valOfA) {
        if (keyOfA == keyOfB && valOfA == valOfB) {
            hasObj = true;
            return false; //If key and value mathed loop will break and no remaining items of second array will be check.
        }
    });

    if (hasObj == false) {
        console.log(keyOfB + "--" + valOfB); //Printing the unmatched key and value
    }

});
0
Mehmood
$scope.ar1 = {A: 10, B: 20, C: 30};

$scope.ar2 = {A: 10, B: 22, C: 30};

$scope.newObj = {};
angular.forEach($scope.ar1, function(v, i) {
    // if ar2[i] is exists and ar2[i] != v then put that value to newObj
    if ($scope.ar2[i] && $scope.ar2[i] != v) {
        $scope.newObj[i] = $scope.ar2[i];
    }
});

console.log($scope.newObj);

hier ist die DEMO

0
K.Toress