Convertendo dict em OrderedDict

138

Estou tendo problemas para usar a collections.OrderedDictclasse. Estou usando o Python 2.7 no Raspbian, a distribuição Debian para o Raspberry Pi. Estou tentando imprimir dois dicionários para comparação (lado a lado) de uma aventura de texto. A ordem é essencial para comparar com precisão. Não importa o que eu tente, os dicionários imprimem da maneira habitual e não ordenada.

Aqui está o que recebo quando faço no meu 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)])

Obviamente, há algo errado, porque está imprimindo a chamada de função e colocando as chaves e os grupos de valores em uma lista aninhada ...

Isto é o que eu consegui executando algo semelhante no meu PC:

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')])

Desta vez, está em ordem, mas não deveria imprimir as outras coisas, certo? (Colocando na lista e mostrando a chamada de função.)

Onde estou cometendo meu erro? Não deve ter nada a ver com a versão pi do Python, porque é apenas a versão Linux.

pythonpiboy
fonte
3
Nota: OrderedDicté classificado por ordem de inserção, não por ordem alfanumérica.
el.pescado

Respostas:

214

Você está criando um dicionário primeiro e depois passando esse dicionário para um OrderedDict. Para versões do Python <3.6 (*) , quando você fizer isso, a ordem não estará mais correta. dicté inerentemente não ordenado.

Passe uma sequência de tuplas:

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

O que você vê quando imprime OrderedDicté sua representação , e está totalmente correto. OrderedDict([('PRICE', 250), ('HP', 50), ('NAME', 'Albatross'), ('BLASTERS', 13), ('THRUSTERS', 18)])mostra apenas, em uma representação reproduzível , quais são os conteúdos do arquivo OrderedDict.


(*) : Na implementação do CPython 3.6, o dicttipo foi atualizado para usar uma estrutura interna mais eficiente em termos de memória que tem o efeito colateral feliz de preservar a ordem de inserção e, por extensão, o código mostrado na pergunta funciona sem problemas. A partir do Python 3.7, a especificação da linguagem Python foi atualizada para exigir que todas as implementações do Python sigam esse comportamento. Veja esta outra resposta minha para obter detalhes e também por que você ainda pode querer usar um OrderedDict()para determinados casos.

Martijn Pieters
fonte
Ok, então o OrderedDict criará o dicionário para mim? Além disso, para imprimir sem a representação reproduzível, posso apenas imprimir a variável OrderedDict usada? ie: print ship ?? Obrigado :)
pythonpiboy 29/03
3
Pergunta: Da maneira que você descreveu, o OrderedDict está fazendo uma "lista" ordenada. Isso não derrota o propósito? É a criação de apenas uma lista de elementos, não dicionários com chaves e valores ...
pythonpiboy
9
O tipo age como ambos; um mapeamento que retém a ordem. Para criar um com ordenação, você precisa dar-lhe itens em ordem . Como um ditado padrão (em algo diferente de PyPI ou Python 3.6+) não pode fazer isso, você fornece uma lista de tuplas. Uma vez que o OrderedDicté criado que é um dicionário.
Martijn Pieters
4
Parece que a confusão é assumir que um OrderedDict "aplica" uma ordem, em vez de apenas reter uma ordem. Eu certamente assumi que classificaria a entrada na criação - ou que a função items () retornaria itens classificados independentemente de quando foram inseridos. Em vez disso, apenas mantém a ordem que você fornecer.
whiterook6
2
@ whiterook6: não é um dicionário classificado não. É um dicionário ordenado, um dicionário que registra a ordem dos pares de valores-chave e permite reordenar esses pares. Compare isso com listas, que são sequências ordenadas .
Martijn Pieters
36

Se você não pode editar esta parte do código onde seu dict foi definido, você ainda pode solicitá-lo a qualquer momento e da forma que desejar, como este:

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 Rozycki
fonte
11

Na maioria das vezes, procuramos o OrderedDict quando solicitamos um pedido personalizado, não genérico como o ASC etc.

Aqui está a solução proposta:

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

Isso será gerado:

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

Nota : Os novos dicionários classificados mantêm sua ordem de classificação quando as entradas são excluídas. Porém, quando novas chaves são adicionadas, elas são anexadas ao final e a classificação não é mantida. ( Documento oficial )

Abdul Majeed
fonte
2

Use dict.items (); pode ser tão simples como a seguir:

ship = collections.OrderedDict(ship.items())
Mohammad-Ali
fonte