update - transformar lista em dicionario python




Como faço para classificar um dicionário por valor? (20)

A partir do Python 3.6, o dict embutido será solicitado

Boas notícias, portanto, o caso de uso original do OP de pares de mapeamento recuperados de um banco de dados com ids de cadeia exclusivos como chaves e valores numéricos como valores em um Python v3.6 + dict integrado agora deve respeitar a ordem de inserção.

Se disser as expressões de tabela de duas colunas resultantes de uma consulta de banco de dados como:

SELECT a_key, a_value FROM a_table ORDER BY a_value;

seria armazenado em duas tuplas do Python, k_seq e v_seq (alinhadas por índice numérico e com o mesmo comprimento de curso), então:

k_seq = ('foo', 'bar', 'baz')
v_seq = (0, 1, 42)
ordered_map = dict(zip(k_seq, v_seq))

Permitir a saída mais tarde como:

for k, v in ordered_map.items():
    print(k, v)

cedendo neste caso (para o novo dict interno do Python 3.6+!):

foo 0
bar 1
baz 42

na mesma ordem por valor de v.

Onde no Python 3.5 instalar na minha máquina, atualmente produz:

bar 1
foo 0
baz 42

Detalhes:

Como proposto em 2012 por Raymond Hettinger (cf. mail em python-dev com assunto "Mais dicionários compactos com iteração mais rápida" ) e agora (em 2016) anunciou em um email por Victor Stinner para python-dev com assunto "Python 3.6 dict se torna compacto e obtém uma versão privada e as palavras-chave são ordenadas " devido à correção / implementação do problema 27350 " Comando compacto e ordenado " no Python 3.6 agora poderemos usar um comando interno para manter a ordem de inserção !!

Espero que isso leve a uma implementação de OrderedDict de camada fina como uma primeira etapa. Como indicado por @ JimFasarakis-Hilliard, alguns vêem casos de uso para o tipo OrderedDict também no futuro. Eu acho que a comunidade Python em geral irá inspecionar cuidadosamente, se isso resistir ao teste do tempo, e quais serão os próximos passos.

Hora de repensar nossos hábitos de codificação para não perder as possibilidades abertas pela ordenação estável de:

  • Argumentos de palavras-chave e
  • armazenamento intermediário (dict)

O primeiro porque facilita o despacho na implementação de funções e métodos em alguns casos.

O segundo, uma vez que incentiva a utilização mais fácil de dict como armazenamento intermediário no processamento de pipelines.

Raymond Hettinger gentilmente forneceu a documentação que explica " A Tech Behind Python 3.6 Dictionaries " - de sua apresentação do Grupo Meetup do San Francisco Python 2016-DEC-08.

E talvez algumas páginas repletas de perguntas e respostas decoradas do Stack Overflow recebam variantes dessa informação, e muitas respostas de alta qualidade também exigirão uma atualização por versão.

Caveat Emptor (mas também veja abaixo a atualização 2017-12-15):

Como o @ajcr observa corretamente: "O aspecto de preservação de pedidos desta nova implementação é considerado um detalhe de implementação e não deve ser confiável." (do whatsnew36 ) não nit picking, mas a citação foi cortada um pouco pessimista ;-). Ele continua como "(isso pode mudar no futuro, mas é desejável ter essa nova implementação de dict na linguagem para algumas liberações antes de alterar a especificação de linguagem para impor a semântica de preservação de ordem para todas as implementações atuais e futuras do Python; ajuda a preservar a compatibilidade retroativa com versões mais antigas da linguagem em que a ordem de iteração aleatória ainda está em vigor, por exemplo, Python 3.5). "

Assim como em algumas linguagens humanas (por exemplo, alemão), o uso molda a linguagem, e a vontade agora foi declarada ... em whatsnew36 .

Atualização 2017-12-15:

Em um email para a lista python-dev , Guido van Rossum declarou:

Faça isso. "Dict mantém ordem de inserção" é a decisão. Obrigado!

Assim, o efeito colateral do CPython versão 3.6 da ordem de inserção de dict agora está se tornando parte da especificação de linguagem (e não mais apenas um detalhe de implementação). Esse segmento de email também apresentou algumas metas de design diferenciadas para collections.OrderedDict lembradas por Raymond Hettinger durante a discussão.

Eu tenho um dicionário de valores lidos de dois campos em um banco de dados: um campo de string e um campo numérico. O campo de string é único, de modo que é a chave do dicionário.

Eu posso classificar as chaves, mas como posso classificar com base nos valores?

Nota: Eu li a pergunta sobre estouro de pilha Como classifico uma lista de dicionários por valores do dicionário em Python? e provavelmente poderia mudar meu código para ter uma lista de dicionários, mas como realmente não preciso de uma lista de dicionários, gostaria de saber se existe uma solução mais simples.


Tão simples quanto: sorted(dict1, key=dict1.get)

Bem, é realmente possível fazer um "ordenar por valores de dicionário". Recentemente eu tive que fazer isso em um Code Golf (pergunta sobre o Code golf: Word frequency chart ). Resumido, o problema era do tipo: dado um texto, conte quantas vezes cada palavra é encontrada e mostre uma lista das palavras principais, classificadas por frequência decrescente.

Se você construir um dicionário com as palavras como chaves e o número de ocorrências de cada palavra como valor, simplificado aqui como:

from collections import defaultdict
d = defaultdict(int)
for w in text.split():
  d[w] += 1

então você pode obter uma lista das palavras, ordenadas por frequência de uso com sorted(d, key=d.get) - o tipo itera sobre as chaves do dicionário, usando o número de ocorrências de palavras como uma chave de classificação.

for w in sorted(d, key=d.get, reverse=True):
  print w, d[w]

Estou escrevendo esta explicação detalhada para ilustrar o que as pessoas costumam dizer com "eu posso facilmente classificar um dicionário por chave, mas como classifico por valor" - e acho que o OP estava tentando resolver esse problema. E a solução é fazer o tipo de lista das chaves, com base nos valores, como mostrado acima.


Claro, lembre-se, você precisa usar o OrderedDict porque os dicionários comuns do Python não mantêm a ordem original.

from collections import OrderedDict
a = OrderedDict(sorted(originalDict.items(), key = lambda x: x[1]))

Se você não tiver o Python 2.7 ou superior, o melhor que você pode fazer é iterar sobre os valores em uma função geradora. (Há um OrderedDict para 2.4 e 2.6 here , mas

a) I don't know about how well it works 

e

b) You have to download and install it of course. If you do not have administrative access, then I'm afraid the option's out.)
def gen(originalDict):
    for x,y in sorted(zip(originalDict.keys(), originalDict.values()), key = lambda z: z[1]):
        yield (x, y)
    #Yields as a tuple with (key, value). You can iterate with conditional clauses to get what you want. 

for bleh, meh in gen(myDict):
    if bleh == "foo":
        print(myDict[bleh])

Você também pode imprimir todos os valores

for bleh, meh in gen(myDict):
    print(bleh,meh)

Por favor, lembre-se de remover os parênteses após a impressão, se não estiver usando o Python 3.0 ou superior


Dado dicionário

e = {1:39, 4:34, 7:110, 2:87}

Classificação

sred = sorted(e.items(), key=lambda value: value[1])

Resultado

[(4, 34), (1, 39), (2, 87), (7, 110)]

Você pode usar uma função lambda para classificar as coisas por valor e armazená-las dentro de uma variável, neste caso sred com o dicionário original.

Espero que ajude!


Este é o código:

import operator
origin_list = [
    {"name": "foo", "rank": 0, "rofl": 20000},
    {"name": "Silly", "rank": 15, "rofl": 1000},
    {"name": "Baa", "rank": 300, "rofl": 20},
    {"name": "Zoo", "rank": 10, "rofl": 200},
    {"name": "Penguin", "rank": -1, "rofl": 10000}
]
print ">> Original >>"
for foo in origin_list:
    print foo

print "\n>> Rofl sort >>"
for foo in sorted(origin_list, key=operator.itemgetter("rofl")):
    print foo

print "\n>> Rank sort >>"
for foo in sorted(origin_list, key=operator.itemgetter("rank")):
    print foo

Aqui estão os resultados:

Original

{'name': 'foo', 'rank': 0, 'rofl': 20000}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Baa', 'rank': 300, 'rofl': 20}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}

Rofl

{'name': 'Baa', 'rank': 300, 'rofl': 20}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
{'name': 'foo', 'rank': 0, 'rofl': 20000}

Classificação

{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
{'name': 'foo', 'rank': 0, 'rofl': 20000}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Baa', 'rank': 300, 'rofl': 20}

Eu inventei esse aqui

import operator    
x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
sorted_x = {k[0]:k[1] for k in sorted(x.items(), key=operator.itemgetter(1))}

Para Python 3.x: x.items() substituindo iteritems() .

>>> sorted_x
{0: 0, 1: 2, 2: 1, 3: 4, 4: 3}

Ou tente com collections.OrderedDict !

x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
from collections import OrderedDict

od1 = OrderedDict(sorted(x.items(), key=lambda t: t[1]))

Isso retorna a lista de pares de valores-chave no dicionário, classificados por valor do maior para o menor:

sorted(d.items(), key=lambda x: x[1], reverse=True)

Para o dicionário classificado por chave, use o seguinte:

sorted(d.items(), reverse=True)

O retorno é uma lista de tuplas porque os próprios dicionários não podem ser classificados.

Isso pode ser impresso ou enviado para mais computação.


Iterar através de um dict e classificá-lo por seus valores em ordem decrescente:

$ python --version
Python 3.2.2

$ cat sort_dict_by_val_desc.py 
dictionary = dict(siis = 1, sana = 2, joka = 3, tuli = 4, aina = 5)
for word in sorted(dictionary, key=dictionary.get, reverse=True):
  print(word, dictionary[word])

$ python sort_dict_by_val_desc.py 
aina 5
tuli 4
joka 3
sana 2
siis 1

Não é possível classificar um dicionário, apenas para obter uma representação de um dicionário que esteja classificado. Dicionários são inerentemente sem ordem, mas outros tipos, como listas e tuplas, não são. Então, você precisa de um tipo de dados ordenado para representar os valores classificados, o que será uma lista - provavelmente uma lista de tuplas.

Por exemplo,

import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(1))

sorted_x será uma lista de tuplas classificadas pelo segundo elemento em cada tupla. dict(sorted_x) == x .

E para aqueles que desejam classificar chaves em vez de valores:

import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(0))

No Python3, já que a descompactação não é permitida [1] , podemos usar

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_by_value = sorted(x.items(), key=lambda kv: kv[1])

No Python 2.7, simplesmente faça:

from collections import OrderedDict
# regular unsorted dictionary
d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

# dictionary sorted by key
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)])

copiar e colar de: http://docs.python.org/dev/library/collections.html#ordereddict-examples-and-recipes

Apreciar ;-)


Quase o mesmo que a resposta de Hank Gay;

    sorted([(value,key) for (key,value) in mydict.items()])

Ou otimizado um pouco como sugerido por John Fouhy;

    sorted((value,key) for (key,value) in mydict.items())


Se os valores forem numéricos, você também pode usar o Contador de coleções

from collections import Counter

x={'hello':1,'python':5, 'world':3}
c=Counter(x)
print c.most_common()


>> [('python', 5), ('world', 3), ('hello', 1)]    

Tecnicamente, dicionários não são seqüências e, portanto, não podem ser classificados. Você pode fazer algo como

sorted(a_dictionary.values())

Supondo que o desempenho não seja um grande negócio.


Tente a seguinte abordagem. Vamos definir um dicionário chamado mydict com os seguintes dados:

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

Se alguém quisesse classificar o dicionário por chaves, poderia fazer algo como:

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

Isso deve retornar a seguinte saída:

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

Por outro lado, se alguém quisesse classificar um dicionário por valor (como é perguntado na pergunta), poderia fazer o seguinte:

for key, value in sorted(mydict.iteritems(), key=lambda (k,v): (v,k)):
    print "%s: %s" % (key, value)

O resultado desse comando (classificando o dicionário por valor) deve retornar o seguinte:

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

Você pode criar um "índice invertido", também

from collections import defaultdict
inverse= defaultdict( list )
for k, v in originalDict.items():
    inverse[v].append( k )

Agora seu inverso tem os valores; cada valor tem uma lista de chaves aplicáveis.

for k in sorted(inverse):
    print k, inverse[k]

Você pode usar a função classificada do Python

sorted(iterable[, cmp[, key[, reverse]]])

Assim você pode usar:

sorted(dictionary.items(),key = lambda x :x[1])

Visite este link para obter mais informações sobre a função classificada: https://docs.python.org/2/library/functions.html#sorted


Você pode usar um skip dict que é um dicionário que é permanentemente classificado por valor.

>>> data = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
>>> SkipDict(data)
{0: 0.0, 2: 1.0, 1: 2.0, 4: 3.0, 3: 4.0}

Se você usar keys() , values() ou items() então você irá iterar em ordem de classificação por valor.

É implementado usando a estrutura de dados da lista de pulos.


Você poderia usar:

sorted(d.items(), key=lambda x: x[1])

Isso classificará o dicionário pelos valores de cada entrada no dicionário, do menor para o maior.


ATUALIZAÇÃO: 5 DE DEZEMBRO DE 2015 usando o Python 3.5

Embora eu achasse a resposta aceita útil, também fiquei surpreso por ela não ter sido atualizada para fazer referência a OrderedDict do módulo de coleções de biblioteca padrão como uma alternativa viável e moderna - criada para resolver exatamente esse tipo de problema.

from operator import itemgetter
from collections import OrderedDict

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = OrderedDict(sorted(x.items(), key=itemgetter(1)))
# OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])

A documentação oficial do OrderedDict oferece um exemplo muito semelhante, mas usando um lambda para a função de classificação:

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

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

Como apontado por Dilettant , o Python 3.6 agora manterá a ordem ! Eu pensei em compartilhar uma função que escrevi que facilita a classificação de uma iterável (tupla, lista, dit). Neste último caso, você pode classificar chaves ou valores e levar em conta a comparação numérica. Apenas para> = 3.6!

Quando você tenta usar classificado em um iterável que contém, por exemplo, strings e ints, o método classificado () falhará. Claro que você pode forçar a comparação de strings com str (). No entanto, em alguns casos, você deseja fazer uma comparação numérica real, em que 12 é menor que 20 (o que não é o caso na comparação de string). Então eu vim com o seguinte. Quando você quiser uma comparação numérica explícita, poderá usar o sinalizador num_as_num que tentará fazer a classificação numérica explícita, tentando converter todos os valores em flutuantes. Se isso for bem-sucedido, ele fará a classificação numérica, caso contrário, ele recorrerá à comparação de strings.

Comentários para melhorias ou solicitações de envio são bem-vindos.

def sort_iterable(iterable, sort_on=None, reverse=False, num_as_num=False):
    def _sort(i):
      # sort by 0 = keys, 1 values, None for lists and tuples
      try:
        if num_as_num:
          if i is None:
            _sorted = sorted(iterable, key=lambda v: float(v), reverse=reverse)
          else:
            _sorted = dict(sorted(iterable.items(), key=lambda v: float(v[i]), reverse=reverse))
        else:
          raise TypeError
      except (TypeError, ValueError):
        if i is None:
          _sorted = sorted(iterable, key=lambda v: str(v), reverse=reverse)
        else:
          _sorted = dict(sorted(iterable.items(), key=lambda v: str(v[i]), reverse=reverse))

      return _sorted

    if isinstance(iterable, list):
      sorted_list = _sort(None)
      return sorted_list
    elif isinstance(iterable, tuple):
      sorted_list = tuple(_sort(None))
      return sorted_list
    elif isinstance(iterable, dict):
      if sort_on == 'keys':
        sorted_dict = _sort(0)
        return sorted_dict
      elif sort_on == 'values':
        sorted_dict = _sort(1)
        return sorted_dict
      elif sort_on is not None:
        raise ValueError(f"Unexpected value {sort_on} for sort_on. When sorting a dict, use key or values")
    else:
      raise TypeError(f"Unexpected type {type(iterable)} for iterable. Expected a list, tuple, or dict")




dictionary