Jak mogę sprawdzić, czy dwa obiekty JSON są równe w Pythonie, pomijając kolejność list?
Na przykład ...
Dokument JSON a :
{
"errors": [
{"error": "invalid", "field": "email"},
{"error": "required", "field": "name"}
],
"success": false
}
Dokument JSON b :
{
"success": false,
"errors": [
{"error": "required", "field": "name"},
{"error": "invalid", "field": "email"}
]
}
a
i b
powinny być równe, mimo że kolejność "errors"
list jest inna.
python
json
django
comparison
Petter Friberg
źródło
źródło
list
elementów też nie ma znaczenia?Odpowiedzi:
Jeśli chcesz, aby dwa obiekty z tymi samymi elementami, ale w innej kolejności były porównywane równo, to oczywistą rzeczą do zrobienia jest porównanie ich posortowanych kopii - na przykład dla słowników reprezentowanych przez twoje ciągi JSON
a
ib
:... ale to nie działa, ponieważ w każdym przypadku
"errors"
element dyktowania najwyższego poziomu jest listą z tymi samymi elementami w innej kolejności isorted()
nie próbuje sortować niczego poza „najwyższym” poziomem iterowalny.Aby to naprawić, możemy zdefiniować
ordered
funkcję, która będzie rekurencyjnie sortować wszystkie znalezione listy (i konwertować słowniki na listy(key, value)
par, aby można je było uporządkować):Jeśli zastosujemy tę funkcję do
a
ib
, wyniki będą równe:źródło
['astr', {'adict': 'something'}]
, jaką otrzymałemTypeError
, próbując je posortować.Innym sposobem może być użycie
json.dumps(X, sort_keys=True)
opcji:Działa to w przypadku zagnieżdżonych słowników i list.
źródło
{"error":"a"}, {"error":"b"}
vs{"error":"b"}, {"error":"a"}
nie będzie w staniejson.dumps({'foo': [3, 1, 2]}, sort_keys=True) == json.dumps({'foo': [2, 1, 3]}, sort_keys=True)
Odszyfruj je i porównaj jako komentarz mgilson.
Porządek nie ma znaczenia dla słownika, jeśli klucze i wartości są zgodne. (Słownik nie ma kolejności w Pythonie)
Ale porządek jest ważny na liście; sortowanie rozwiąże problem dotyczący list.
Powyższy przykład zadziała dla JSON w pytaniu. Ogólne rozwiązanie można znaleźć w odpowiedzi Zero Piraeus.
źródło
Dla następujących dwóch dykt „dictWithListsInValue” i „reorderedDictWithReorderedListsInValue”, które są po prostu zmienionymi wersjami siebie
dał mi zły wynik, tj. fałszywy.
Stworzyłem więc własny cutstom ObjectComparator w następujący sposób:
co dało mi prawidłowe oczekiwane wyjście!
Logika jest dość prosta:
Jeśli obiekty są typu „lista”, porównaj każdą pozycję z pierwszej listy z pozycjami z drugiej listy, aż do znalezienia, a jeśli pozycja nie zostanie znaleziona po przejrzeniu drugiej listy, to „znaleziony” będzie miał wartość = fałsz. Zwracana jest wartość „znaleziona”
W przeciwnym razie, jeśli porównywane obiekty są typu „dict”, porównaj wartości obecne dla wszystkich odpowiednich kluczy w obu obiektach. (Wykonywane jest porównanie rekurencyjne)
W przeciwnym razie po prostu wywołaj obj1 == obj2. Domyślnie działa dobrze dla obiektu łańcuchów i liczb oraz dla tych eq () jest odpowiednio zdefiniowane.
(Zwróć uwagę, że algorytm można dalej ulepszyć, usuwając elementy znalezione w object2, aby następny element object1 nie porównywał się z elementami już znalezionymi w object2)
źródło
Możesz napisać własną funkcję równości:
a == b
Ponieważ mamy do czynienia z json, musisz standardowe typy Pythona:
dict
,list
, itd., Więc można zrobić twardy sprawdzanie typuif type(obj) == 'dict':
itdSzorstki przykład (nie testowano):
źródło
Dla innych, którzy chcieliby debugować dwa obiekty JSON (zwykle jest to odniesienie i cel ), oto rozwiązanie, którego możesz użyć. Wyświetli listę „ ścieżka ” różnych / niedopasowanych od celu do odniesienia.
level
Opcja służy do wyboru, jak głęboko chcesz zajrzeć.show_variables
można włączyć, aby wyświetlić odpowiednią zmienną.źródło