Python - Restituisce la prima chiave N: coppie di valori da dict


109

Considera il seguente dizionario, d:

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

Voglio restituire la prima chiave N: coppie di valori da d (N <= 4 in questo caso). Qual è il metodo più efficiente per farlo?


1
Attenzione. Sembra esserci molta disinformazione nelle risposte. I miei test mostrano che non una singola soluzione è più veloce di list(d.items())[:4]. list () è l'implementazione sottostante per molte delle risposte.
BSalita

Risposte:


115

Non esiste una cosa del genere per le "prime n" chiavi perché a dictnon ricorda quali chiavi sono state inserite per prime.

È possibile ottenere tutte le coppie chiave-valore n però:

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

Questo utilizza l'implementazione di takedalle itertoolsricette :

from itertools import islice

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

Guardalo in linea: ideone


Aggiornamento per Python 3.6

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

42
Credo che iteritemsdovrebbe essere sostituito con itemsper gente su Python 3
Monica Heddneck

1
@MonicaHeddneck, geniale, grazie per aver aggiunto questo commento.
Karl Baker

12
Principiante qui - fa take()parte della base del codice Python da qualche parte? Oppure è puramente la funzione che hai definito nella tua risposta qui? Chiedendo come se fosse una parte del codice di base, non sono in grado di trovarlo / importarlo. :)
Scott Borden

81

Un modo molto efficiente per recuperare qualsiasi cosa è combinare le comprensioni di elenchi o dizionari con l'affettatura. Se non hai bisogno di ordinare gli articoli (vuoi solo n coppie casuali), puoi usare una comprensione del dizionario come questa:

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

Generalmente una comprensione come questa è sempre più veloce da eseguire rispetto all'equivalente ciclo "for x in y". Inoltre, usando .keys () per creare un elenco delle chiavi del dizionario e affettando quell'elenco, eviti di "toccare" qualsiasi tasto non necessario quando crei il nuovo dizionario.

Se non hai bisogno delle chiavi (solo dei valori) puoi usare una comprensione dell'elenco:

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

Se hai bisogno dei valori ordinati in base alle loro chiavi, non c'è molto più problema:

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

o se hai bisogno anche delle chiavi:

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

2
Questa è una soluzione migliore se si desidera selezionare N molte coppie chiave: valore come dizionario, non come elenco
fermat4214

1
@ fermat4214 È un problema se il mio intero dizionario viene stampato quando eseguo uno di questi comandi?
Ted Taylor of Life,

list (mydict) [: 2] è uno spreco se non hai bisogno di ordinare il dizionario e hai bisogno solo dei primi 2 elementi. E se il dizionario avesse 1 mil kv di coppie? Convertire l'intera cosa in un elenco è costoso. La soluzione di Mark Byers è molto migliore.
JJ

Questa dovrebbe essere la soluzione!
Guenter,

14

Le dictchiavi di Python non sono ordinate, quindi non ha senso chiedere le "prime N" chiavi.

La collections.OrderedDictclasse è disponibile se è quello che ti serve. Puoi ottenere in modo efficiente i suoi primi quattro elementi come

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.isliceti permette di prendere pigramente una fetta di elementi da qualsiasi iteratore. Se vuoi che il risultato sia riutilizzabile, devi convertirlo in un elenco o qualcosa del genere, in questo modo:

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

Non sembrare pigro. Richiede due volte più tempo di `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))

Fondamentalmente, trasforma la vista (dict_items) in un iteratore, quindi itera con next ().


2
Risposta fantastica, questa è l'unica risposta su questa pagina che ha funzionato per me ed è anche leggibile. Inoltre, posso verificare che funzioni con Python 3, cosa che alcune delle risposte precedenti non sembrano.
cdahms

7

Non l'ho visto qui. Non verrà ordinato ma sintatticamente il più semplice se è necessario prendere solo alcuni elementi da un dizionario.

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

7
Ho provato il tuo codice ma ottengo questo errore: TypeError: 'dict_items' object is not subscriptable {key:value for key,value in stocks.items()[0:n]} (stock è il nome del mio dizionario)
Moondra

2
@ Moondra - Devi convertire nell'elenco prima di scorrere gli elementi del dizionario. Sopra il codice, la riga funziona se {key: value for key, value in list (d.items ()) [0: n]}
Rajesh Mappu

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

6

Per ottenere i primi N elementi dal tuo dizionario Python, puoi usare la seguente riga di codice:

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

Nel tuo caso puoi cambiarlo in:

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

3

Vedere PEP 0265 sull'ordinamento dei dizionari. Quindi utilizzare il suddetto codice iterabile.

Se hai bisogno di maggiore efficienza nelle coppie chiave-valore ordinate. Usa una struttura dati diversa. Ovvero, uno che mantiene l'ordine ordinato e le associazioni valore-chiave.

Per esempio

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

in py3, questo farà il trucco

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

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


2

basta aggiungere una risposta usando zip,

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

1

Dipende da cosa è "più efficiente" nel tuo caso.

Se vuoi solo un campione semi-casuale di un enorme dizionario foo, usa foo.iteritems()e prendi tutti i valori di cui hai bisogno, è un'operazione pigra che evita la creazione di un elenco esplicito di chiavi o elementi.

Se devi prima ordinare le chiavi, non c'è modo di usare qualcosa come keys = foo.keys(); keys.sort()o sorted(foo.iterkeys()), dovrai creare un elenco esplicito di chiavi. Poi tagliare o iterare primo N keys.

BTW perché ti interessa il modo "efficiente"? Hai profilato il tuo programma? Se non l'hai fatto, usa prima il modo ovvio e facile da capire . È probabile che andrà abbastanza bene senza diventare un collo di bottiglia.


Questa era un'applicazione per un programma finanziario e cerco di creare ogni riga di codice nel modo più efficiente possibile. Non ho profilato il programma e sono d'accordo che probabilmente non sarà un collo di bottiglia, ma mi piace chiedere soluzioni efficienti per impostazione predefinita. Grazie per la risposta.
Jason Strimpel

0

Puoi avvicinarti a questo in molti modi. Se l'ordine è importante, puoi farlo:

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

Se l'ordine non è un problema, puoi farlo:

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

Nel primo snippet dovresti probabilmente chiamarlo valuepiuttosto che itemper chiarezza.
agf

0

Il dizionario non mantiene l'ordine, quindi prima di scegliere le prime N coppie di valori chiave, è necessario ordinarlo.

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

Ora possiamo recuperare i primi 'N' elementi :, usando la struttura del metodo in questo modo:

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

per ottenere i primi 2 elementi, usa semplicemente questa struttura:

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

Per Python 3 e versioni successive, selezionare le prime n coppie

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

0

considera un dict

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

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

islice farà il trucco :) spero che aiuti!


0

Questo potrebbe non essere molto elegante, ma per me funziona:

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

Ho provato alcune delle risposte sopra e ho notato che alcune dipendono dalla versione e non funzionano nella versione 3.7.

Noto anche che dalla 3.6 tutti i dizionari sono ordinati in base alla sequenza in cui sono inseriti gli elementi.

Nonostante i dizionari siano stati ordinati a partire dalla versione 3.6, alcune delle affermazioni che ci si aspetta funzionino con strutture ordinate non sembrano funzionare.

La risposta alla domanda OP che ha funzionato meglio per me.

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

Cordiali saluti, 5 volte più lento dilst = 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="")

Approccio insolito, poiché emette un'intensa complessità del tempo O (N).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.