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});
}
})
});
});
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 a
name__. Die Eigenschaft b
ist nicht dieselbe. Nur x
hat eine Eigenschaft c
name__, und nur y
hat eine Eigenschaft d
name__. Also, was sollte ???
genau sein?
Aus der Sicht von diff
kann die Beziehung zwischen unseren Eingabeobjekten a
und b
völlig beliebig sein. Um mitzuteilen, welches Objekt zu einer Differenz beiträgt, weist diff
Deskriptoren left
und right
zu.
console.log (diff (x, y))
// { b: { left: 2, right: 3 }, c: { left: 3 }, d: { right: 4 } }
In der Ausgabe oben können wir sehen
b
name__, c
und d
name__left
und/oder right
name__b
den Wert 2, der rechte b
den Wert 3; oder der linke c
hat einen Wert von 3, der rechte c
hat einen Wert von undefinedBevor 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 diff
eine Struktur zurück, die unseren Eingaben entspricht. Und schließlich erwarten wir, dass der diff
von 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 diff
name__, 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 merge
name__, 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 merge
kombiniert 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, rel
name__. 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 original
und modified
aussagekräftiger sind als left
und right
name__.
Zusammenführen
Alles, was bleibt, ist das Zusammenführen der beiden Halbdifferenzen zu einem vollständigen Ergebnis. Unsere Funktion merge
funktioniert 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 merge
ebenfalls 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 merge
name__
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 diff
zurückblicken, möchte ich einen wichtigen Teil ihres Designs hervorheben. Ein guter Teil der Arbeit wird von der Funktion merge
erledigt, die völlig unabhängig von diff
ist, 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 diff
haben wollten, haben wir es bekommen, und wir haben eine intuitive, tiefe merge
name__-Funktionalität gratis bekommen.
extra: Unterstützung für Arrays
Unsere Funktion diff
ist 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 diff
vollständig unverändert
// unchanged
const diff = (x = {}, y = {}) =>
merge
( diff1 (x, y, "left")
, diff1 (y, x, "right")
)
Um Arrays in merge
zu unterstützen, führen wir einen Mutation Helper mut
ein, der einem bestimmten Objekt, o
name__, ein [ key, value ]
-Paar zuweist. Arrays werden ebenfalls als Objekte betrachtet, sodass wir sowohl Arrays als auch Objekte mit derselben Funktion mut
aktualisieren 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 diff
zum 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 union
anstelle eines diff
name__
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.
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);
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));
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;
}
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
}
});
$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