Python - Retourne la première clé N: paires de valeurs de dict

109

Considérez le dictionnaire suivant, d:

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

Je veux retourner la première clé N: paires de valeurs de d (N <= 4 dans ce cas). Quelle est la méthode la plus efficace pour y parvenir?

Jason Strimpel
la source
1
Mise en garde. Semble être beaucoup de désinformation dans les réponses. Mes tests montrent qu'aucune solution n'est plus rapide que list(d.items())[:4]. list () est l'implémentation sous-jacente de nombreuses réponses.
BSalita le

Réponses:

115

Les «premières n» clés dictn'existent pas car a ne se souvient pas quelles clés ont été insérées en premier.

Vous pouvez obtenir toutes les paires clé-valeur n cependant:

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

Celui - ci utilise la mise en œuvre takedes itertoolsrecettes :

from itertools import islice

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

Regardez-le fonctionner en ligne: ideone


Mise à jour pour Python 3.6

n_items = take(n, d.items())
Mark Byers
la source
42
Je pense que iteritemsdevrait être remplacé par itemspour les gens sur Python 3
Monica Heddneck
1
@MonicaHeddneck, génial, merci d'avoir ajouté ce commentaire.
Karl Baker
12
Débutant ici - fait take()partie de la base de code python quelque part? Ou est-ce uniquement la fonction que vous avez définie dans votre réponse ici? En demandant comme si cela faisait partie de la base de code, je ne suis pas en mesure de le trouver / de l'importer. :)
Scott Borden le
81

Un moyen très efficace de récupérer quoi que ce soit est de combiner des compréhensions de liste ou de dictionnaire avec le découpage. Si vous n'avez pas besoin de commander les éléments (vous voulez juste n paires aléatoires), vous pouvez utiliser une compréhension de dictionnaire comme celle-ci:

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

En général, une telle compréhension est toujours plus rapide à exécuter que l'équivalent de la boucle «for x in y». De plus, en utilisant .keys () pour créer une liste des clés du dictionnaire et en découpant cette liste, vous évitez de «toucher» les touches inutiles lorsque vous créez le nouveau dictionnaire.

Si vous n'avez pas besoin des clés (uniquement les valeurs), vous pouvez utiliser une compréhension de liste:

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

Si vous avez besoin que les valeurs soient triées en fonction de leurs clés, ce n'est pas beaucoup plus de problèmes:

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

ou si vous avez également besoin des clés:

first2pairs = {k: mydict[k] for k in sorted(mydict.keys())[:2]}
monotasker
la source
2
Celui-ci est une meilleure solution si vous voulez sélectionner N plusieurs paires clé: valeur comme dictionnaire, pas comme liste
fermat4214
1
@ fermat4214 Est-ce un problème, si tout mon dictionnaire s'imprime lorsque j'exécute l'une de ces commandes?
Ted Taylor of Life
list (mydict) [: 2] est inutile si vous n'avez pas besoin de trier le dictionnaire et n'avez besoin que des 2 premiers éléments. Et si le dictionnaire a 1 mil paires de kv? Convertir le tout en liste coûte cher. La solution de Mark Byers est bien meilleure.
JJ
Cela devrait être la solution!
Guenter le
14

Python dict s ne sont pas ordonnés, il est donc inutile de demander les «premières N» clés.

Le collections.OrderedDictcours est disponible si c'est ce dont vous avez besoin. Vous pouvez efficacement obtenir ses quatre premiers éléments comme

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.islicevous permet de prendre paresseusement une tranche d'éléments de n'importe quel itérateur. Si vous voulez que le résultat soit réutilisable, vous devez le convertir en une liste ou quelque chose comme ceci:

x = list(itertools.islice(d.items(), 0, 4))
Jérémie
la source
Pas l'air paresseux. Prend 2 fois plus de temps 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))

En gros, transformez la vue (dict_items) en itérateur, puis itérez-la avec next ().

cop4587
la source
2
Réponse fantastique, c'est la seule réponse sur cette page qui a fonctionné pour moi et qui est également lisible. De plus, je peux vérifier que cela fonctionne avec Python 3, ce que certaines des réponses les plus anciennes ne semblent pas faire.
cdahms
7

Je ne l'ai pas vu ici. Ne sera pas ordonné mais syntaxiquement le plus simple si vous avez juste besoin de prendre quelques éléments d'un dictionnaire.

n = 2
{key:value for key,value in d.items()[0:n]}
user2623954
la source
7
J'ai essayé votre code mais j'obtiens cette erreur: TypeError: 'dict_items' object is not subscriptable {key:value for key,value in stocks.items()[0:n]} (stocks est le nom de mon dictionnaire)
Moondra
2
@Moondra - Vous devez convertir dans la liste avant de parcourir les éléments du dictionnaire. Au-dessus du code, la ligne fonctionne si {key: value for key, value in list (d.items ()) [0: n]}
Rajesh Mappu
{A: N pour (A, N) dans [x pour x dans d.items ()] [: 4]}
farid khafizov
6

Pour obtenir les N premiers éléments de votre dictionnaire python, vous pouvez utiliser la ligne de code suivante:

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

Dans votre cas, vous pouvez le changer en:

list(d.items())[:4]
thevatsalsaglani
la source
3

Voir PEP 0265 sur le tri des dictionnaires. Ensuite, utilisez le code itératif mentionné ci-dessus.

Si vous avez besoin de plus d'efficacité dans les paires clé-valeur triées. Utilisez une structure de données différente. Autrement dit, celui qui maintient l'ordre trié et les associations clé-valeur.

Par exemple

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
la source
3

dans py3, cela fera l'affaire

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

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

farid khafizov
la source
2

ajoutez simplement une réponse en utilisant zip,

{k: d[k] for k, _ in zip(d, range(n))}
Peter Li
la source
1

Cela dépend de ce qui est «le plus efficace» dans votre cas.

Si vous voulez juste un échantillon semi-aléatoire d'un énorme dictionnaire foo, utilisez foo.iteritems()et prenez autant de valeurs que vous le souhaitez, c'est une opération paresseuse qui évite la création d'une liste explicite de clés ou d'éléments.

Si vous devez d'abord trier les clés, il n'y a aucun moyen d'utiliser quelque chose comme keys = foo.keys(); keys.sort()ou sorted(foo.iterkeys()), vous devrez créer une liste explicite de clés. Puis couper ou itérer à travers le premier N keys.

BTW pourquoi vous souciez-vous de la manière «efficace»? Avez-vous profilé votre programme? Si vous ne l'avez pas fait, utilisez d' abord la méthode évidente et facile à comprendre . Il y a de fortes chances que cela se passe plutôt bien sans devenir un goulot d'étranglement.

9 000
la source
Il s'agissait d'une application à un programme financier et j'essaie de créer chaque ligne de code aussi efficacement que possible. Je n'ai pas profilé le programme et je suis d'accord que ce ne sera probablement pas un goulot d'étranglement, mais j'aime demander des solutions efficaces par défaut. Merci pour la réponse.
Jason Strimpel
0

Vous pouvez aborder cela de plusieurs façons. Si l'ordre est important, vous pouvez le faire:

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

Si la commande n'est pas un problème, vous pouvez le faire:

for i in range(4):
  item = d.popitem()
gddc
la source
Dans le premier extrait, vous devriez probablement l'appeler valueplutôt que itempour plus de clarté.
agf
0

Le dictionnaire ne maintient aucun ordre, donc avant de choisir les N meilleures paires de valeurs clés, faisons le tri.

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

Maintenant, nous pouvons faire la récupération des éléments 'N' supérieurs :, en utilisant la structure de méthode comme ceci:

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

pour obtenir les 2 premiers éléments, utilisez simplement cette structure:

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
la source
0

Pour Python 3 et supérieur, pour sélectionner les n premières paires

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

considérer 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 fera l'affaire :) j'espère que cela vous aidera!

Vivek Ananthan
la source
0

Cela n'est peut-être pas très élégant, mais fonctionne pour moi:

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
la source
0

J'ai essayé quelques-unes des réponses ci-dessus et je note que certaines d'entre elles dépendent de la version et ne fonctionnent pas dans la version 3.7.

Je note également que depuis 3.6 tous les dictionnaires sont classés selon l'ordre dans lequel les éléments sont insérés.

Bien que les dictionnaires soient commandés depuis la version 3.6, certaines des instructions que vous prévoyez de travailler avec des structures ordonnées ne semblent pas fonctionner.

La réponse à la question OP qui a le mieux fonctionné pour moi.

itr = iter(dic.items())
lst = [next(itr) for i in range(3)]
Mark Kortink
la source
FYI, 5 fois plus lent 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="")

Approche inhabituelle, car elle donne une intense complexité temporelle O (N).

Shashwata Shastri
la source