Konwertowanie dict na OrderedDict

138

Mam problemy z używaniem tej collections.OrderedDictklasy. Używam Pythona 2.7 na Raspbian, dystrybucji Debiana dla Raspberry Pi. Próbuję wydrukować dwa słowniki w celu porównania (obok siebie) do przygody z tekstem. Kolejność jest niezbędna do dokładnego porównania. Bez względu na to, czego próbuję, słowniki drukują w zwykły, nieuporządkowany sposób.

Oto, co otrzymuję, robiąc to na moim RPi:

import collections

ship = {"NAME": "Albatross",
         "HP":50,
         "BLASTERS":13,
         "THRUSTERS":18,
         "PRICE":250}

ship = collections.OrderedDict(ship)

print ship
# OrderedDict([('PRICE', 250), ('HP', 50), ('NAME', 'Albatross'), ('BLASTERS', 13), ('THRUSTERS', 18)])

Oczywiście coś jest nie tak, ponieważ wypisuje wywołanie funkcji i umieszcza klucze i grupy wartości w zagnieżdżonej liście ...

Oto, co otrzymałem, uruchamiając coś podobnego na moim komputerze:

import collections

Joe = {"Age": 28, "Race": "Latino", "Job": "Nurse"}
Bob = {"Age": 25, "Race": "White", "Job": "Mechanic", "Random": "stuff"}

#Just for clarity:
Joe = collections.OrderedDict(Joe)
Bob = collections.OrderedDict(Bob)

print Joe
# OrderedDict([('Age', 28), ('Race', 'Latino'), ('Job', 'Nurse')])
print Bob
# OrderedDict([('Age', 25), ('Race', 'White'), ('Job', 'Mechanic'), ('Random', 'stuff')])

Tym razem jest w porządku, ale nie powinno się drukować innych rzeczy, prawda? (Umieszczenie go na liście i pokazanie wywołania funkcji.)

Gdzie popełniam błąd? Nie powinno to mieć nic wspólnego z wersją pi Pythona, ponieważ jest to tylko wersja dla Linuksa.

pythonpiboy
źródło
3
Uwaga: OrderedDictjest sortowany według kolejności reklamowej, a nie alfanumerycznej kolejności kluczy.
el.pescado

Odpowiedzi:

214

Najpierw tworzysz słownik , a następnie przekazujesz go do pliku OrderedDict. W przypadku wersji Pythona <3.6 (*) , do czasu gdy to zrobisz, kolejność nie będzie już poprawna. dictz natury nie jest uporządkowany.

Zamiast tego podaj sekwencję krotek:

ship = [("NAME", "Albatross"),
        ("HP", 50),
        ("BLASTERS", 13),
        ("THRUSTERS", 18),
        ("PRICE", 250)]
ship = collections.OrderedDict(ship)

To, co widzisz, gdy drukujesz, OrderedDictjest jego reprezentacją i jest całkowicie poprawne. OrderedDict([('PRICE', 250), ('HP', 50), ('NAME', 'Albatross'), ('BLASTERS', 13), ('THRUSTERS', 18)])po prostu pokazuje, w możliwej do odtworzenia reprezentacji, jaka jest zawartość pliku OrderedDict.


(*) : W implementacji CPython 3.6, dicttyp został zaktualizowany, aby używać bardziej wydajnej pamięci wewnętrznej struktury, która ma szczęśliwy efekt uboczny w postaci zachowania kolejności wstawiania, a przez rozszerzenie kod pokazany w pytaniu działa bez problemów. Od wersji Python 3.7 specyfikacja języka Python została zaktualizowana, aby wymagać, aby wszystkie implementacje Pythona były zgodne z tym zachowaniem. Zobacz tę inną moją odpowiedź, aby uzyskać szczegółowe informacje, a także dlaczego nadal możesz chcieć użyć OrderedDict()w niektórych przypadkach.

Martijn Pieters
źródło
Ok, więc OrderedDict utworzy dla mnie słownik? Ponadto, aby wydrukować bez odtwarzalnej reprezentacji, czy mogę po prostu wydrukować zmienną OrderedDict, w której jest używana? tj .: print ship ?? Dzięki :)
pythonpiboy
3
Pytanie: W sposób, który opisałeś, OrderedDict tworzy uporządkowaną „listę”. Czy to nie pokonuje celu? Tworzy tylko listę elementów, a nie słowniki z kluczami i wartościami ...
pythonpiboy
9
Typ działa jak oba; mapowanie, które zachowuje porządek. Aby utworzyć jedną z zamawiania, trzeba dać mu elementy w kolejności . Ponieważ standardowe dyktowanie (na czymkolwiek innym niż PyPI lub Python 3.6+) nie może tego zrobić, zamiast tego podajesz mu listę krotek. Gdy OrderedDictjest tworzona to jest słownik.
Martijn Pieters
4
Wygląda na to, że zamieszanie wynika z założenia, że ​​OrderedDict „stosuje” polecenie, a nie tylko je zachowuje. Z pewnością założyłem, że posortuje dane wejściowe podczas tworzenia - lub że funkcja items () zwróci posortowane elementy niezależnie od tego, kiedy zostały wstawione. Zamiast tego po prostu zachowuje to, co podasz.
whiterook6
2
@ whiterook6: to nie jest posortowany słownik nr. Jest to słownik uporządkowany, słownik, który rejestruje kolejność par klucz-wartość i umożliwia zmianę kolejności tych par. Porównaj to z listami, które są uporządkowanymi sekwencjami .
Martijn Pieters
36

Jeśli nie możesz edytować tej części kodu, w której zdefiniowano twój dykt, nadal możesz go zamówić w dowolnym momencie w dowolny sposób, na przykład:

from collections import OrderedDict

order_of_keys = ["key1", "key2", "key3", "key4", "key5"]
list_of_tuples = [(key, your_dict[key]) for key in order_of_keys]
your_dict = OrderedDict(list_of_tuples)
Jan Różycki
źródło
11

Przez większość czasu korzystamy z OrderedDict, gdy wymagaliśmy niestandardowego zamówienia, a nie ogólnego, takiego jak ASC itp.

Oto proponowane rozwiązanie:

import collections
ship = {"NAME": "Albatross",
         "HP":50,
         "BLASTERS":13,
         "THRUSTERS":18,
         "PRICE":250}

ship = collections.OrderedDict(ship)

print ship


new_dict = collections.OrderedDict()
new_dict["NAME"]=ship["NAME"]
new_dict["HP"]=ship["HP"]
new_dict["BLASTERS"]=ship["BLASTERS"]
new_dict["THRUSTERS"]=ship["THRUSTERS"]
new_dict["PRICE"]=ship["PRICE"]


print new_dict

To wyświetli:

OrderedDict([('PRICE', 250), ('HP', 50), ('NAME', 'Albatross'), ('BLASTERS', 13), ('THRUSTERS', 18)])
OrderedDict([('NAME', 'Albatross'), ('HP', 50), ('BLASTERS', 13), ('THRUSTERS', 18), ('PRICE', 250)])

Uwaga : Nowe posortowane słowniki zachowują porządek sortowania po usunięciu wpisów. Ale kiedy dodawane są nowe klucze, są one dołączane na końcu, a sortowanie nie jest utrzymywane. ( Oficjalny dokument )

Abdul Majeed
źródło
2

Użyj dict.items (); może to być tak proste, jak:

ship = collections.OrderedDict(ship.items())
Mohammad-Ali
źródło