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?

Jason Strimpel
fonte
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())
Mark Byers
fonte
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]}
monotarefa
fonte
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))
Jeremy
fonte
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 ().

cop4587
fonte
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]}
user2623954
fonte
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]
thevatsalsaglani
fonte
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)]
Silverjam
fonte
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}

farid khafizov
fonte
2

basta adicionar uma resposta usando zip,

{k: d[k] for k, _ in zip(d, range(n))}
Peter Li
fonte
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.

9000
fonte
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()
gddc
fonte
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)
Jyothish Arumugam
fonte
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]}
Shivpe_R
fonte
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!

Vivek Ananthan
fonte
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
Thorsten Stehlik
fonte
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)]
Mark Kortink
fonte
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.

Shashwata Shastri
fonte