Comment puis-je tester si deux objets JSON sont égaux en python, sans tenir compte de l'ordre des listes?
Par exemple ...
Document JSON a :
{
"errors": [
{"error": "invalid", "field": "email"},
{"error": "required", "field": "name"}
],
"success": false
}
Document JSON b :
{
"success": false,
"errors": [
{"error": "required", "field": "name"},
{"error": "invalid", "field": "email"}
]
}
a
et b
devrait comparer égaux, même si l'ordre des "errors"
listes est différent.
python
json
django
comparison
Petter Friberg
la source
la source
list
éléments n'a pas d'importance non plus?Réponses:
Si vous voulez que deux objets avec les mêmes éléments mais dans un ordre différent se comparent égaux, alors la chose évidente à faire est de comparer des copies triées d'entre eux - par exemple, pour les dictionnaires représentés par vos chaînes JSON
a
etb
:... mais cela ne fonctionne pas, car dans chaque cas, l'
"errors"
élément du dict de niveau supérieur est une liste avec les mêmes éléments dans un ordre différent, etsorted()
n'essaye pas de trier autre chose que le niveau "supérieur" de un itérable.Pour résoudre ce problème, nous pouvons définir une
ordered
fonction qui triera de manière récursive toutes les listes trouvées (et convertira les dictionnaires en listes de(key, value)
paires afin qu'ils puissent être triés):Si nous appliquons cette fonction à
a
etb
, les résultats se comparent égaux:la source
['astr', {'adict': 'something'}]
, j'aiTypeError
quand j'essaye de les trier.Une autre façon pourrait être d'utiliser l'
json.dumps(X, sort_keys=True)
option:Cela fonctionne pour les dictionnaires et les listes imbriqués.
la source
{"error":"a"}, {"error":"b"}
vs{"error":"b"}, {"error":"a"}
il ne sera pas en mesure de trier ce dernier cas dans le premier casjson.dumps({'foo': [3, 1, 2]}, sort_keys=True) == json.dumps({'foo': [2, 1, 3]}, sort_keys=True)
Décodez-les et comparez-les en tant que commentaire mgilson.
L'ordre n'a pas d'importance pour le dictionnaire tant que les clés et les valeurs correspondent. (Le dictionnaire n'a pas d'ordre en Python)
Mais l'ordre est important dans la liste; le tri résoudra le problème des listes.
L'exemple ci-dessus fonctionnera pour le JSON dans la question. Pour une solution générale, voir la réponse de Zero Piraeus.
la source
Pour les deux dictionnaires suivants 'dictWithListsInValue' et 'reorderedDictWithReorderedListsInValue' qui sont simplement des versions réorganisées l'une de l'autre
m'a donné un mauvais résultat, c'est-à-dire faux.
J'ai donc créé mon propre ObjectComparator cutstom comme ceci:
ce qui m'a donné la sortie correcte attendue!
La logique est assez simple:
Si les objets sont de type «liste», comparez chaque élément de la première liste avec les éléments de la deuxième liste jusqu'à ce qu'ils soient trouvés, et si l'élément n'est pas trouvé après avoir parcouru la deuxième liste, alors «trouvé» serait = faux. La valeur 'found' est renvoyée
Sinon, si les objets à comparer sont de type «dict», comparez les valeurs présentes pour toutes les clés respectives dans les deux objets. (Une comparaison récursive est effectuée)
Sinon, appelez simplement obj1 == obj2. Par défaut, cela fonctionne bien pour l'objet de chaînes et de nombres et pour ceux-ci, eq () est défini de manière appropriée.
(Notez que l'algorithme peut encore être amélioré en supprimant les éléments trouvés dans object2, de sorte que l'élément suivant de object1 ne se compare pas avec les éléments déjà trouvés dans l'objet2)
la source
Vous pouvez écrire votre propre fonction égale:
a == b
Parce que vous avez affaire à JSON, vous aurez les types de python standard:
dict
,list
, etc., de sorte que vous pouvez faire la vérification de type durif type(obj) == 'dict':
, etc.Exemple approximatif (non testé):
la source
Pour les autres qui souhaitent déboguer les deux objets JSON (généralement, il y a une référence et une cible ), voici une solution que vous pouvez utiliser. Il listera le " chemin " des différents / incompatibles de la cible à la référence.
level
L'option est utilisée pour sélectionner la profondeur à laquelle vous souhaitez examiner.show_variables
L'option peut être activée pour afficher la variable appropriée.la source