Python - retorna a primeira chave N: pares de valor de dict


109

Considere o seguinte dicionário, d:

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

Desejo retornar a primeira N pares chave: valor de d (N <= 4 neste caso). Qual é o método mais eficiente de fazer isso?


1
Cuidado. Parece haver muita desinformação nas respostas. Meus testes mostram que nenhuma solução é mais rápida do que list(d.items())[:4]. list () é a implementação subjacente para muitas das respostas.
BSalita

Respostas:


115

Não existe tal coisa de "primeiras n" chaves porque um dict não lembra quais chaves foram inseridas primeiro.

Você pode obter quaisquer n pares de valores-chave:

n_items = take(n, d.iteritems())

Isso usa a implementação de takedas itertoolsreceitas :

from itertools import islice

def take(n, iterable):
    "Return first n items of the iterable as a list"
    return list(islice(iterable, n))

Veja funcionando online: ideone


Atualização para Python 3.6

n_items = take(n, d.items())

42
Eu acredito que iteritemsdeveria ser substituído por itemspara pessoas no Python 3
Monica Heddneck

1
@MonicaHeddneck, brilhante, obrigado por adicionar este comentário.
Karl Baker

12
Iniciante aqui - faz take()parte da base de código python em algum lugar? Ou é puramente a função que você definiu em sua resposta aqui? Perguntando como se fosse parte da base do código, não consigo localizar / importar. :)
Scott Borden

81

Uma maneira muito eficiente de recuperar qualquer coisa é combinar as compreensões de lista ou dicionário com o fatiamento. Se você não precisa ordenar os itens (você só quer n pares aleatórios), você pode usar uma compreensão de dicionário como esta:

# Python 2
first2pairs = {k: mydict[k] for k in mydict.keys()[:2]}
# Python 3
first2pairs = {k: mydict[k] for k in list(mydict)[:2]}

Geralmente, uma compreensão como essa é sempre mais rápida de executar do que o loop equivalente "for x in y". Além disso, ao usar .keys () para fazer uma lista das chaves do dicionário e dividir essa lista, você evita 'tocar' em quaisquer teclas desnecessárias ao construir o novo dicionário.

Se você não precisa das chaves (apenas os valores), você pode usar uma compreensão de lista:

first2vals = [v for v in mydict.values()[:2]]

Se você precisa dos valores classificados com base em suas chaves, não é muito mais problema:

first2vals = [mydict[k] for k in sorted(mydict.keys())[:2]]

ou se você também precisar das chaves:

first2pairs = {k: mydict[k] for k in sorted(mydict.keys())[:2]}

2
Esta é uma solução melhor se você deseja selecionar N muitos pares de chave: valor como um dicionário, não como uma lista
fermat4214

1
@ fermat4214 É um problema se todo o meu dicionário for impresso quando executo qualquer um desses comandos?
Ted Taylor of Life

list (mydict) [: 2] é um desperdício se você não precisar classificar o dicionário e precisar apenas dos 2 primeiros elementos. E se o dicionário tiver pares de 1 mil kv? Converter tudo em uma lista é caro. A solução de Mark Byers é muito melhor.
JJ

Essa deve ser a solução!
Guenter

14

Os dicts do Python não são ordenados, portanto, não faz sentido solicitar as "primeiras N" chaves.

A collections.OrderedDictaula está disponível se você precisar. Você pode obter com eficiência seus primeiros quatro elementos, como

import itertools
import collections

d = collections.OrderedDict((('foo', 'bar'), (1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')))
x = itertools.islice(d.items(), 0, 4)

for key, value in x:
    print key, value

itertools.islicepermite que você preguiçosamente pegue uma fatia de elementos de qualquer iterador. Se você quiser que o resultado seja reutilizável, você precisará convertê-lo em uma lista ou algo assim:

x = list(itertools.islice(d.items(), 0, 4))

Não parecendo preguiçoso. Leva 2x mais do que `list (d.items ()) [: 4]
BSalita

12
foo = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5, 'f':6}
iterator = iter(foo.items())
for i in range(3):
    print(next(iterator))

Basicamente, transforme a visão (dict_items) em um iterador e, em seguida, itere com next ().


2
Resposta fantástica, esta é a única resposta nesta página que funcionou para mim e também é legível. Além disso, posso verificar que isso funciona com Python 3, o que algumas das respostas mais antigas parecem não funcionar.
cdahms

7

Não vi aqui. Não será ordenado, mas o mais simples sintaticamente se você precisar apenas pegar alguns elementos de um dicionário.

n = 2
{key:value for key,value in d.items()[0:n]}

7
Tentei seu código, mas recebo este erro: TypeError: 'dict_items' object is not subscriptable {key:value for key,value in stocks.items()[0:n]} (ações é o nome do meu dicionário)
Moondra

2
@Moondra - Tem que converter na lista antes de percorrer os itens do dicionário. Acima do código, a linha funciona se {chave: valor para chave, valor na lista (d.items ()) [0: n]}
Rajesh Mappu

{A: N for (A, N) in [x for x in d.items ()] [: 4]}
farid khafizov

6

Para obter os N principais elementos de seu dicionário Python, pode-se usar a seguinte linha de código:

list(dictionaryName.items())[:N]

No seu caso, você pode alterá-lo para:

list(d.items())[:4]

3

Veja PEP 0265 sobre classificação de dicionários. Em seguida, use o código iterável mencionado anteriormente.

Se você precisar de mais eficiência nos pares de valores-chave classificados. Use uma estrutura de dados diferente. Ou seja, aquele que mantém a ordem de classificação e as associações de valor-chave.

Por exemplo

import bisect

kvlist = [('a', 1), ('b', 2), ('c', 3), ('e', 5)]
bisect.insort_left(kvlist, ('d', 4))

print kvlist # [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]

3

em py3, isso fará o truque

{A:N for (A,N) in [x for x in d.items()][:4]}

{'a': 3, 'b': 2, 'c': 3, 'd': 4}


2

basta adicionar uma resposta usando zip,

{k: d[k] for k, _ in zip(d, range(n))}

1

Isso depende do que é "mais eficiente" no seu caso.

Se você quiser apenas uma amostra semi-aleatória de um dicionário enorme foo, use foo.iteritems()e retire quantos valores forem necessários, é uma operação preguiçosa que evita a criação de uma lista explícita de chaves ou itens.

Se você precisar classificar as chaves primeiro, não há como evitar o uso de algo como keys = foo.keys(); keys.sort()ou sorted(foo.iterkeys()), você terá que construir uma lista explícita de chaves. Em seguida, divida ou itere através dos primeiros Nkeys .

BTW, por que você se preocupa com a maneira 'eficiente'? Você definiu o perfil do seu programa? Caso contrário, use primeiro o caminho óbvio e fácil de entender . Provavelmente, ele funcionará muito bem, sem se tornar um gargalo.


Este era um aplicativo para um programa financeiro e tento construir cada linha de código da forma mais eficiente possível. Não criei o perfil do programa e concordo que provavelmente não será um gargalo, mas gosto de pedir soluções eficientes por padrão. Obrigado pela resposta.
Jason Strimpel

0

Você pode abordar isso de várias maneiras. Se o pedido for importante, você pode fazer o seguinte:

for key in sorted(d.keys()):
  item = d.pop(key)

Se o pedido não for uma preocupação, você pode fazer o seguinte:

for i in range(4):
  item = d.popitem()

No primeiro trecho, você provavelmente deve chamá-lo em valuevez de itempara maior clareza.
agf

0

O dicionário não mantém nenhuma ordem, portanto, antes de escolher os N principais pares de valores-chave, vamos classificá-lo.

import operator
d = {'a': 3, 'b': 2, 'c': 3, 'd': 4}
d=dict(sorted(d.items(),key=operator.itemgetter(1),reverse=True))
#itemgetter(0)=sort by keys, itemgetter(1)=sort by values

Agora podemos fazer a recuperação dos principais elementos 'N' :, usando a estrutura do método como esta:

def return_top(elements,dictionary_element):
    '''Takes the dictionary and the 'N' elements needed in return
    '''
    topers={}
    for h,i in enumerate(dictionary_element):
        if h<elements:
            topers.update({i:dictionary_element[i]})
    return topers

para obter os 2 principais elementos, basta usar esta estrutura:

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4}
d=dict(sorted(d.items(),key=operator.itemgetter(1),reverse=True))
d=return_top(2,d)
print(d)

0

Para Python 3 e acima, para selecionar os primeiros n pares

n=4
firstNpairs = {k: Diction[k] for k in list(Diction.keys())[:n]}

0

considere um ditado

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

from itertools import islice
n = 3
list(islice(d.items(),n))

islice resolverá :) espero que ajude!


0

Isso pode não ser muito elegante, mas funciona para mim:

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

x= 0
for key, val in d.items():
    if x == 2:
        break
    else:
        x += 1
        # Do something with the first two key-value pairs

0

Tentei algumas das respostas acima e observe que algumas delas dependem da versão e não funcionam na versão 3.7.

Também observo que desde 3.6 todos os dicionários são ordenados pela sequência em que os itens são inseridos.

Apesar de os dicionários serem solicitados desde 3.6, algumas das instruções que você espera que funcionem com estruturas ordenadas parecem não funcionar.

A resposta à pergunta do OP que funcionou melhor para mim.

itr = iter(dic.items())
lst = [next(itr) for i in range(3)]

Para sua informação, 5x mais lento quelst = list(d.items())[:N]
BSalita

0
def GetNFirstItems(self):
    self.dict = {f'Item{i + 1}': round(uniform(20.40, 50.50), 2) for i in range(10)}#Example Dict
    self.get_items = int(input())
    for self.index,self.item in zip(range(len(self.dict)),self.dict.items()):
        if self.index==self.get_items:
          break
        else:
            print(self.item,",",end="")

Abordagem incomum, pois dá complexidade de tempo O (N) intensa.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.