Como posso classificar um dicionário por chave?

940

Qual seria uma boa maneira de passar de {2:3, 1:89, 4:5, 3:0}para {1:89, 2:3, 3:0, 4:5}?
Eu verifiquei algumas postagens, mas todas elas usam o operador "classificado" que retorna tuplas.

Antony
fonte
39
Os dicionários são intrinsecamente não classificados. A exibição do dicionário é outra questão. Enfim, para que você realmente precisa classificá-lo?
30912 Karl Knechtel
15
dicionários não são classificados. eles simplesmente não estão. se você quiser passar pelos elementos na ordem, precisará fazer algo como disse usando ordenado, como "para digitar ordenado (d.keys ())", assumindo que d é o nome do seu dicionário
Ryan Haining
3
@KarlKnechtel - meu caso de uso é que eu tenho um aplicativo CLI que possui um menu primitivo e as opções de menu estão em um dicionário como as chaves. Gostaria de exibir as chaves em ordem alfabética para garantir a sanidade do usuário.
Randy
4
Observe que os ditados agora são ordenados por ordem de inserção (python 3.6+). Algumas respostas abaixo apontam isso.
matiasg

Respostas:

940

Os dicionários Python padrão não são ordenados. Mesmo se você classificasse os pares (chave, valor), não seria possível armazená-los de dictuma maneira que preservasse a ordem.

A maneira mais fácil é usar OrderedDict, que lembra a ordem na qual os elementos foram inseridos:

In [1]: import collections

In [2]: d = {2:3, 1:89, 4:5, 3:0}

In [3]: od = collections.OrderedDict(sorted(d.items()))

In [4]: od
Out[4]: OrderedDict([(1, 89), (2, 3), (3, 0), (4, 5)])

Não importa o modo como odestá impresso; funcionará como esperado:

In [11]: od[1]
Out[11]: 89

In [12]: od[3]
Out[12]: 0

In [13]: for k, v in od.iteritems(): print k, v
   ....: 
1 89
2 3
3 0
4 5

Python 3

Para usuários do Python 3, é necessário usar o em .items()vez de .iteritems():

In [13]: for k, v in od.items(): print(k, v)
   ....: 
1 89
2 3
3 0
4 5
NPE
fonte
1
Eu usei isso e ele funciona, acho que é mais código e redundância, mas faz o trabalho, # unordered dict d = {2: 3, 1:89, 4: 5, 3: 0} ordersDict = {} para digitar ordenados (d.iterkeys ()): ordersDict [chave] = d [chave]
Antony
4
@achrysochoou: se funcionou, deve ter sido por pura sorte. Como foi informado, os dicionários regulares não têm conceito de classificação, independentemente de você atribuir as chaves classificadas ou de maneira aleatória.
Ricardo Cárdenes
21
Para python 3.7+:sorted_dict = dict(sorted(unsorted_dict.items()))
aksh1618
10
python 3.7+ não deve precisar orderedDict uma vez que agora ordens por padrão :-)
Aneuway
3
No manual do python 3.7.4: "A execução da lista (d) em um dicionário retorna uma lista de todas as chaves usadas no dicionário, em ordem de inserção". Portanto, a ordem de inserção é algo que é preservado e em que podemos confiar.
Mostafa Hadian
415

Os próprios dicionários não possuem itens solicitados como tal, caso você queira imprimi-los etc. em alguma ordem, aqui estão alguns exemplos:

No Python 2.4 e acima:

mydict = {'carl':40,
          'alan':2,
          'bob':1,
          'danny':3}

for key in sorted(mydict):
    print "%s: %s" % (key, mydict[key])

dá:

alan: 2
bob: 1
carl: 40
danny: 3

(Python abaixo de 2,4 :)

keylist = mydict.keys()
keylist.sort()
for key in keylist:
    print "%s: %s" % (key, mydict[key])

Fonte: http://www.saltycrane.com/blog/2007/09/how-to-sort-python-dictionary-by-keys/

James
fonte
2
Você também pode usar OrderedDict em python 2.4 + como na do NPE resposta
radtek
1
e se você estiver usando items (), pode fazê-lo comofor key, value in sorted(mydict.items())"
beep_check 04/02
Os próprios dicionários não têm itens ordenados como tal -> não são mais verdadeiros!
minexew 6/04
Como é que você pode explicar?
James
204

Na documentação da collectionsbiblioteca do Python :

>>> from collections import OrderedDict

>>> # regular unsorted dictionary
>>> d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

>>> # dictionary sorted by key -- OrderedDict(sorted(d.items()) also works
>>> OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])

>>> # dictionary sorted by value
>>> OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

>>> # dictionary sorted by length of the key string
>>> OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])
Dennis
fonte
4
impressionante! Pessoal, se você quiser reverter a ordem (ascendente TO descendente), basta adicionar, reverse=Truepor exemplo OrderedDict(sorted(d.items(), reverse=True, key=lambda t: t[0]))
,:
1
Em PyCharm, não importa o dicionário que eu uso, eu sempre chegar este aviso:Unexpected type(s): (List[str]) Possible types: (Mapping) (Iterable[Tuple[Any, Any]])
Euler_Salter
153

Para o CPython / PyPy 3.6 e qualquer Python 3.7 ou superior, isso é feito facilmente com:

>>> d = {2:3, 1:89, 4:5, 3:0}
>>> dict(sorted(d.items()))
{1: 89, 2: 3, 3: 0, 4: 5}
Dipu
fonte
3
Outra maneira de escrever a mesma coisa é usar uma compreensão: {key:d[key] for key in sorted(d.keys())}
flow2k 27/11/19
41

Existem vários módulos Python que fornecem implementações de dicionário que mantêm automaticamente as chaves na ordem de classificação. Considere o módulo de contêineres classificados , que é uma implementação pura em Python e rápida como C. Há também uma comparação de desempenho com outras opções populares comparadas entre si.

Usar um ditado ordenado é uma solução inadequada se você precisar adicionar e remover constantemente pares de chave / valor enquanto também itera.

>>> from sortedcontainers import SortedDict
>>> d = {2:3, 1:89, 4:5, 3:0}
>>> s = SortedDict(d)
>>> s.items()
[(1, 89), (2, 3), (3, 0), (4, 5)]

O tipo SortedDict também suporta pesquisas e exclusão de locais indexados, o que não é possível com o tipo de dict interno.

>>> s.iloc[-1]
4
>>> del s.iloc[2]
>>> s.keys()
SortedSet([1, 2, 4])
GrantJ
fonte
32

Simplesmente:

d = {2:3, 1:89, 4:5, 3:0}
sd = sorted(d.items())

for k,v in sd:
    print k, v

Resultado:

1 89
2 3
3 0
4 5
user3769249
fonte
6
sdé uma lista de tuplas, não um dicionário. (embora ainda útil.)
nischi
24

Como outros mencionaram, os dicionários são inerentemente desordenados. No entanto, se o problema estiver apenas exibindo dicionários de maneira ordenada, você poderá substituir o __str__método em uma subclasse de dicionário e usar essa classe de dicionário em vez do incorporado dict. Por exemplo.

class SortedDisplayDict(dict):
   def __str__(self):
       return "{" + ", ".join("%r: %r" % (key, self[key]) for key in sorted(self)) + "}"


>>> d = SortedDisplayDict({2:3, 1:89, 4:5, 3:0})
>>> d
{1: 89, 2: 3, 3: 0, 4: 5}

Observe que isso não muda nada sobre como as chaves são armazenadas, a ordem em que elas voltarão quando você iterar sobre elas, etc., exatamente como elas são exibidas printno console do python ou no console.

Brian
fonte
19

Encontrou outra maneira:

import json
print json.dumps(d, sort_keys = True)

upd:
1. isso também classifica objetos aninhados (obrigado @DanielF).
2. Os dicionários python não são ordenados, portanto, é possível imprimir ou atribuir apenas a str.

tschesseket
fonte
Mas isso também classifica as chaves de objetos aninhados, que podem não ser desejadas.
21715 Daniel F
Observe que isso apenas classifica dicionários, não listas, por exemplo, dict.keys () não será classificado porque é uma lista.
Andrew
16

No Python 3.

>>> D1 = {2:3, 1:89, 4:5, 3:0}
>>> for key in sorted(D1):
    print (key, D1[key])

1 89
2 3
3 0
4 5
Evgeny Tryastsin
fonte
13

O dicionário Python não era ordenado antes do Python 3.6. Na implementação do Python 3.6 do CPython, o dicionário mantém a ordem de inserção. A partir do Python 3.7, isso se tornará um recurso de linguagem.

No log de alterações do Python 3.6 ( https://docs.python.org/3.6/whatsnew/3.6.html#whatsnew36-compactdict ):

O aspecto de preservação de pedidos dessa nova implementação é considerado um detalhe da implementação e não deve ser considerado (isso pode mudar no futuro, mas é desejável que essa nova implementação de ditado no idioma seja liberada algumas vezes antes de alterar as especificações do idioma. para exigir a semântica de preservação de pedidos para todas as implementações atuais e futuras do Python, isso também ajuda a preservar a compatibilidade com versões anteriores da linguagem em que a ordem de iteração aleatória ainda está em vigor, por exemplo, Python 3.5).

No documento do Python 3.7 ( https://docs.python.org/3.7/tutorial/datastructures.html#dictionaries ):

A execução da lista (d) em um dicionário retorna uma lista de todas as chaves usadas no dicionário, em ordem de inserção (se você deseja que seja classificada, basta usar a classificação (d)).

Portanto, diferente das versões anteriores, você pode classificar um ditado após o Python 3.6 / 3.7. Se você deseja classificar um dict aninhado, incluindo o subdict dentro, é possível:

test_dict = {'a': 1, 'c': 3, 'b': {'b2': 2, 'b1': 1}}

def dict_reorder(item):
    return {k: sort_dict(v) if isinstance(v, dict) else v for k, v in sorted(item.items())}

reordered_dict = dict_reorder(test_dict)

https://gist.github.com/ligyxy/f60f0374defc383aa098d44cfbd318eb

Guangyang Li
fonte
11

Aqui encontrei uma solução mais simples para classificar o ditado python por chave usando pprint. por exemplo.

>>> x = {'a': 10, 'cd': 20, 'b': 30, 'az': 99} 
>>> print x
{'a': 10, 'b': 30, 'az': 99, 'cd': 20}

mas enquanto estiver usando o pprint, ele retornará o ditado classificado

>>> import pprint 
>>> pprint.pprint(x)
{'a': 10, 'az': 99, 'b': 30, 'cd': 20}
Atul Arvind
fonte
10

Existe uma maneira fácil de classificar um dicionário.

De acordo com sua pergunta,

A solução é :

c={2:3, 1:89, 4:5, 3:0}
y=sorted(c.items())
print y

(Onde c, é o nome do seu dicionário.)

Este programa fornece a seguinte saída:

[(1, 89), (2, 3), (3, 0), (4, 5)]

como você queria.

Outro exemplo é:

d={"John":36,"Lucy":24,"Albert":32,"Peter":18,"Bill":41}
x=sorted(d.keys())
print x

Dá a saída:['Albert', 'Bill', 'John', 'Lucy', 'Peter']

y=sorted(d.values())
print y

Dá a saída:[18, 24, 32, 36, 41]

z=sorted(d.items())
print z

Dá a saída:

[('Albert', 32), ('Bill', 41), ('John', 36), ('Lucy', 24), ('Peter', 18)]

Por isso, alterando-o em chaves, valores e itens, você pode imprimir como o que você queria.

Sree
fonte
8

Gerará exatamente o que você deseja:

 D1 = {2:3, 1:89, 4:5, 3:0}

 sort_dic = {}

 for i in sorted(D1):
     sort_dic.update({i:D1[i]})
 print sort_dic


{1: 89, 2: 3, 3: 0, 4: 5}

Mas essa não é a maneira correta de fazer isso, porque, poderia mostrar um comportamento distinto com diferentes dicionários, que aprendi recentemente. Por isso, Tim sugeriu o caminho perfeito na resposta da minha consulta que estou compartilhando aqui.

from collections import OrderedDict
sorted_dict = OrderedDict(sorted(D1.items(), key=lambda t: t[0]))
jax
fonte
O que significa "mostrar um comportamento distinto com dicionários diferentes"? Qual é o "comportamento distinto" que a classificação não pode lidar?
ingyhere
6

Acho que a coisa mais fácil é classificar o ditado por chave e salvar a chave classificada: par de valores em um novo ditado.

dict1 = {'renault': 3, 'ford':4, 'volvo': 1, 'toyota': 2} 
dict2 = {}                  # create an empty dict to store the sorted values
for key in sorted(dict1.keys()):
    if not key in dict2:    # Depending on the goal, this line may not be neccessary
        dict2[key] = dict1[key]

Para tornar mais claro:

dict1 = {'renault': 3, 'ford':4, 'volvo': 1, 'toyota': 2} 
dict2 = {}                  # create an empty dict to store the sorted     values
for key in sorted(dict1.keys()):
    if not key in dict2:    # Depending on the goal, this line may not be  neccessary
        value = dict1[key]
        dict2[key] = value
lallolu
fonte
6

Você pode criar um novo dicionário, classificando o dicionário atual por chave, conforme sua pergunta.

Este é o seu dicionário

d = {2:3, 1:89, 4:5, 3:0}

Crie um novo dicionário d1 classificando este d usando a função lambda

d1 = dict(sorted(d.items(), key = lambda x:x[0]))

d1 deve ser {1: 89, 2: 3, 3: 0, 4: 5}, classificado com base nas chaves em d.

Amit Prafulla
fonte
5

Os dictos Python não são ordenados. Normalmente, isso não é um problema, pois o caso de uso mais comum é fazer uma pesquisa.

A maneira mais simples de fazer o que você deseja seria criar uma collections.OrderedDictinserção dos elementos na ordem de classificação.

ordered_dict = collections.OrderedDict([(k, d[k]) for k in sorted(d.keys())])

Se você precisar iterar, como sugeriram outros acima, a maneira mais simples seria iterar sobre as chaves classificadas. Exemplos-

Imprimir valores classificados por chaves:

# create the dict
d = {k1:v1, k2:v2,...}
# iterate by keys in sorted order
for k in sorted(d.keys()):
    value = d[k]
    # do something with k, value like print
    print k, value

Obter lista de valores classificados por chaves:

values = [d[k] for k in sorted(d.keys())]
Ramashish Baranwal
fonte
2
for k,value in sorted(d.items()):é melhor: evita acessar o ditado por chave novamente no loop
Jean-François Fabre
4

Eu venho com uma classificação de ditado de linha única.

>> a = {2:3, 1:89, 4:5, 3:0}
>> c = {i:a[i] for i in sorted(a.keys())}
>> print(c)
{1: 89, 2: 3, 3: 0, 4: 5}
[Finished in 0.4s]

Espero que isso seja útil.

Jeevan Chaitanya
fonte
4

Esta função classifica qualquer dicionário recursivamente por sua chave. Ou seja, se algum valor no dicionário também for um dicionário, ele também será classificado por sua chave. Se você estiver executando no CPython 3.6 ou superior, é possível fazer uma simples alteração para usar um em dictvez de um OrderedDict.

from collections import OrderedDict

def sort_dict(d):
    items = [[k, v] for k, v in sorted(d.items(), key=lambda x: x[0])]
    for item in items:
        if isinstance(item[1], dict):
            item[1] = sort_dict(item[1])
    return OrderedDict(items)
    #return dict(items)
Booboo
fonte
2

Gente, você está complicando as coisas ... é bem simples

from pprint import pprint
Dict={'B':1,'A':2,'C':3}
pprint(Dict)

A saída é:

{'A':2,'B':1,'C':3}
Derick Fdo
fonte
Promovido o voto porque eu não conhecia os dicionários pprint sortes para exibi-los, mas o OP realmente perguntou sobre "ir" de ditado não classificado para ordenado, ou seja, o OP parece querer algo que permaneça classificado na memória, talvez para algum algoritmo que exija chaves classificadas
Captain Lepton
Este método não permitirá atribuição encadeada, pois pprint não retorna nenhum. >>> adict = {'B': 1, 'A': 2, 'C': 3} >>> ppdict = pprint (adict) {'A': 2, 'B': 1, 'C': 3} >>> ppdict.type () Traceback (última chamada mais recente): Arquivo "<stdin>", linha 1, em <module> AttributeError: o objeto 'NoneType' não possui atributo 'type'
2

A solução mais simples é que você deve obter uma lista da ordem de classificação do dict e depois iterar sobre o dict. Por exemplo

a1 = {'a':1, 'b':13, 'd':4, 'c':2, 'e':30}
a1_sorted_keys = sorted(a1, key=a1.get, reverse=True)
for r in a1_sorted_keys:
    print r, a1[r]

A seguir, será apresentada a saída (ordem de pedido)

e 30
b 13
d 4
c 2
a 1
Shafiq
fonte
2

Uma maneira fácil de fazer isso:

d = {2:3, 1:89, 4:5, 3:0}

s = {k : d[k] for k in sorted(d)}

s
Out[1]: {1: 89, 2: 3, 3: 0, 4: 5} 
pr94
fonte
1

Uma comparação de tempo dos dois métodos no 2.7 mostra que eles são praticamente idênticos:

>>> setup_string = "a = sorted(dict({2:3, 1:89, 4:5, 3:0}).items())"
>>> timeit.timeit(stmt="[(k, val) for k, val in a]", setup=setup_string, number=10000)
0.003599141953657181

>>> setup_string = "from collections import OrderedDict\n"
>>> setup_string += "a = OrderedDict({1:89, 2:3, 3:0, 4:5})\n"
>>> setup_string += "b = a.items()"
>>> timeit.timeit(stmt="[(k, val) for k, val in b]", setup=setup_string, number=10000)
0.003581275490432745 
Jesuisme
fonte
1
from operator import itemgetter
# if you would like to play with multiple dictionaries then here you go:
# Three dictionaries that are composed of first name and last name.
user = [
    {'fname': 'Mo', 'lname': 'Mahjoub'},
    {'fname': 'Abdo', 'lname': 'Al-hebashi'},
    {'fname': 'Ali', 'lname': 'Muhammad'}
]
#  This loop will sort by the first and the last names.
# notice that in a dictionary order doesn't matter. So it could put the first name first or the last name first. 
for k in sorted (user, key=itemgetter ('fname', 'lname')):
    print (k)

# This one will sort by the first name only.
for x in sorted (user, key=itemgetter ('fname')):
    print (x)
Mohammad Mahjoub
fonte
1
dictionary = {1:[2],2:[],5:[4,5],4:[5],3:[1]}

temp=sorted(dictionary)
sorted_dict = dict([(k,dictionary[k]) for i,k in enumerate(temp)])

sorted_dict:
         {1: [2], 2: [], 3: [1], 4: [5], 5: [4, 5]}
Mahdi Ghelichi
fonte
0

Minha sugestão é essa, pois permite que você ordene um ditado ou mantenha um ditado classificado enquanto adiciona itens e pode precisar adicionar itens no futuro:

Construa a dictpartir do zero à medida que avança. Tenha uma segunda estrutura de dados, uma lista, com sua lista de chaves. O pacote bisect possui uma função de classificação, que permite inserir em uma lista classificada ou classificar sua lista após preencher completamente seu ditado. Agora, quando você itera sobre seu ditado, em vez disso, itera sobre a lista para acessar cada chave de maneira ordenada, sem se preocupar com a representação da estrutura do dict (que não foi feita para classificação).

demongolem
fonte
-1
l = dict.keys()
l2 = l
l2.append(0)
l3 = []
for repeater in range(0, len(l)):
    smallnum = float("inf")
    for listitem in l2:
        if listitem < smallnum:
            smallnum = listitem
    l2.remove(smallnum)
    l3.append(smallnum)
l3.remove(0)
l = l3

for listitem in l:
    print(listitem)
user7070507
fonte
3
Existem 14 outras respostas. Você pode explicar um pouco o seu código e por que ele pode ser melhor do que as outras soluções?
FelixSFD
Downvoted - Código bastante ilegível com nomes curtos de variáveis ​​sem sentido l, l2, l3. Parece ser uma tentativa de um algoritmo indireto e ineficiente sem o conhecimento das funções padrão do python e, de qualquer forma, não funciona quando testado em um pequeno exemplo no post original.
Captain Lepton