J'ai deux objets:
1)
{A: 10, B: 20, C: 30}
2)
{A: 10, B: 22, C: 30}
comme vous pouvez le voir: il y a presque des égaux, sauf une chose: la clé B
valeur est différente.
Comment puis-je entrer dans mes différences someNewArr
clé-valeur?
comme someNewArr
: {B: 22}
(j'obtiens les valeurs du deuxième objet)
j'utilise angular, et je veux dire quelque chose comme ça:
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});
}
})
});
});
diff récursif
Presque trois ans plus tard, je suis heureux de fournir une réponse actualisée à cette question.
Nous commençons avec deux objets différents
const x =
{ a: 1, b: 2, c: 3 }
const y =
{ a: 1, b: 3, d: 4 }
console.log (diff (x, y))
// => ???
Les deux objets ont la même propriété a
name__. La propriété b
n'est pas la même. Seul x
a une propriété c
et seul y
a une propriété d
name__. Alors, que devrait ???
être exactement?
Du point de vue de diff
name__, la relation entre nos objets d’entrée a
et b
pourrait être complètement arbitraire. diff
attribue des descripteurs left
et right
name__
console.log (diff (x, y))
// { b: { left: 2, right: 3 }, c: { left: 3 }, d: { right: 4 } }
Dans la sortie ci-dessus, nous pouvons voir
b
name__, c
et d
name__left
et/ou right
name__b
a la valeur 2, la droite b
a la valeur 3; ou la gauche c
a une valeur de 3, la droite c
a une valeur de non définiAvant de commencer à implémenter cette fonction, nous allons d'abord examiner un scénario plus complexe impliquant des objets profondément imbriqués.
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 } } } }
Comme nous pouvons le voir ci-dessus, diff
renvoie une structure qui correspond à nos entrées. Et enfin, nous nous attendons à ce que diff
de deux objets identiques renvoie un résultat "vide"
const x1 =
{ a: 1, b: { c: { d: 2 } } }
const x2 =
{ a: 1, b: { c: { d: 2 } } }
console.log (diff (x1, x2))
// {}
Nous décrivons ci-dessus une fonction diff
qui ne se soucie pas des objets d'entrée qui lui sont donnés L'objet "gauche" peut contenir des clés que l'objet "droite" ne contient pas, et inversement, nous devons néanmoins détecter les modifications des deux côtés. À partir d'un niveau élevé, voici comment nous aborderons le problème
const diff = (x = {}, y = {}) =>
merge
( diff1 (x, y, "left")
, diff1 (y, x, "right")
)
diff1
Nous prenons un diff "unilatéral" en utilisant diff1
décrit comme la relation "gauche", et nous prenons un autre diff unilatéral avec les objets en entrée inversés décrits comme la relation "droite", puis nous merge
les deux résultats ensemble
Notre travail est divisé pour nous en tâches plus faciles à accomplir maintenant. diff1
n'a besoin que de détecter la moitié des modifications nécessaires et merge
combine simplement les résultats. Nous allons commencer par 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
accepte deux objets d'entrée et un descripteur de relation, rel
name__. La valeur par défaut de ce descripteur est "left"
, qui est "l'orientation" par défaut de la comparaison. Notez ci-dessous que diff1
ne fournit que la moitié du résultat dont nous avons besoin. Inverser les arguments dans un appel seconde à diff1
fournit l'autre moitié.
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 } }
Il convient également de noter que les étiquettes de relation "left"
et "right"
sont définissables par l'utilisateur. Par exemple, si vous avez une relation connue entre les objets que vous comparez et que vous souhaitez fournir des étiquettes plus descriptives dans la sortie diff ...
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' } }
Dans l'exemple ci-dessus, il peut être plus facile de travailler avec la sortie dans d'autres zones de votre programme car les étiquettes original
et modified
sont plus descriptives que left
et right
name__.
fusionner
Il ne reste plus qu'à fusionner les deux demi-différences pour obtenir un résultat complet. Notre fonction merge
fonctionne également de manière générique et accepte deux objets quelconques en entrée.
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 }
Si chaque objet contient une propriété dont la valeur est aussi un objet, merge
se reproduira et fusionnera également les objets imbriqués.
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 }
Ci-dessous, nous codons nos intentions dans 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
)
Et c'est tout le kit et caboodle! Développez l'extrait de code ci-dessous pour exécuter une démonstration de code dans votre propre navigateur.
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)))
// {}
remarques
Lorsque nous examinons notre fonction diff
name__, je souhaite mettre en évidence une partie importante de sa conception. Une bonne partie du travail est gérée par la fonction merge
name__, qui est complètement distincte de diff
name__, et pourtant, un ough nut to crack à lui tout seul. Puisque nous avons séparé nos préoccupations en fonctions uniques, il est maintenant facile de les réutiliser dans d’autres domaines de votre programme. Où nous voulions diff
name__, nous l'avons, et nous avons la fonctionnalité intuitive intuitive merge
gratuitement.
extra: support pour les tableaux
Notre fonction diff
est très pratique car elle peut analyser des objets profondément imbriqués, mais que se passe-t-il si l'une de nos propriétés d'objet est un tableau? Ce serait bien si nous pouvions différer les tableaux en utilisant la même technique.
La prise en charge de cette fonctionnalité nécessite des modifications non triviales du code ci-dessus. Cependant, la majorité de la structure et du raisonnement restent les mêmes. Par exemple, diff
est totalement inchangé.
// unchanged
const diff = (x = {}, y = {}) =>
merge
( diff1 (x, y, "left")
, diff1 (y, x, "right")
)
Pour prendre en charge les tableaux de merge
name__, nous introduisons un assistant de mutation mut
qui attribue une paire [ key, value ]
à un objet donné, o
name__. Les tableaux sont également considérés comme des objets. Nous pouvons donc mettre à jour les tableaux et les objets en utilisant la même fonction mut
name__.
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)
Peu profonde fusionne le travail comme prévu
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 ]
Et la fusion profonde aussi
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 } ] }
La prise en charge des tableaux dans diff1
est considérablement plus complexe
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) ? [] : {}
)
Mais avec ces changements en place, nous pouvons maintenant comparer en profondeur les objets contenant des tableaux - et même les tableaux contenant des objets!
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 }
// }
Étant donné que diff1
modifie soigneusement son comportement en fonction de ses types d'entrée, nous obtenons un tableau différent gratuitement
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))
// []
Exécutez le programme complet dans votre navigateur ci-dessous
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 }
// }
peu profonde diff
La version précédente de cette réponse fournissait une fonction objet diff
permettant de comparer des objets avec les mêmes clés et de comparer des objets avec des clés différentes, mais aucune des deux solutions ne procédait de manière récursive aux objets imbriqués.
union récursive
Dans this Q & R , nous prenons deux objets d'entrée et calculons un union
récursif au lieu d'un diff
name__
Cette solution n'est pas angulaire, mais cela pourrait aider.
Il faudra 2 objets avec un nombre quelconque de clés, et ils n'ont pas besoin de contenir les mêmes clés.
** Sortie: ** 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 );
J'espère que ça aide.
La solution est assez simple,
Initialisez votre tableau,
var resultArray = [];
parcourez ensuite les clés de votre objet, en en utilisant une comme référence (en supposant que les objets possèdent les mêmes clés, mais que vous souhaitiez vérifier les clés contenant des valeurs différentes)
et enfin exécuter le code simple
for(let key in obj){
// console.log(key);
if(obj[key] !== this.profileObject[key] ){
resultArray.Push(key);
}
}
Et récupère ta réponse à la fin
console.log(resultArray);
Cela retournera le diff du premier argument par rapport au second argument. Je n'utilise pas angular.forEach ici cependant.
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));
J'espère que cela t'aidera. Je l'ai fait avec la fonction jQuery each
.
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);
voici la DEMO