J'ai le dictionnaire suivant:

'{0: 0, 1: 11, 2: 26, 3: 43, 4: 14, 5: 29, 6: 34, 7: 49, 8: 49, 9: 108, 10: 124, 11: 108, 12: 361, 13: 290, 14: 2118, 15: 5408, 16: 43473, 17: 109462, 18: 111490, 19: 244675, 20: 115878, 21: 6960}'

Et pour ce dictionnaire, je veux écrire une fonction qui renvoie les trois paires clé-valeur qui ont les valeurs les plus élevées (donc dans ce cas, clé 18, 19, 20).

J'ai trouvé ce qui suit:

cachedict = nr_of_objects_per_century() #Dictionary mentioned above

def top_3_centuries():
        max_nr_works_list = sorted(cachedict.values())
        top_3_values = []
        for i in range(len(max_nr_works_list)-3, len(max_nr_works_list)):
            top_3_values.append(max_nr_works_list[i])
            print(top_3_values)

Cela me donne une liste des valeurs maximales que je veux rechercher. Mais comment dois-je procéder à partir d'ici? Existe-t-il un moyen de le faire sans recherche inversée (ce qui est lent pour les dictionnaires, n'est-ce pas?) J'ai le sentiment que je peux faire cette tâche beaucoup plus efficacement / pythonique.

6
Psychotechnopath 20 nov. 2018 à 13:03

8 réponses

Meilleure réponse

Vous pouvez également utiliser collections.Counter avec most_common (qui utilise en interne une file d'attente de tas):

from collections import Counter

dct = {0: 0, 1: 11, 2: 26, 3: 43, 4: 14, 5: 29, 6: 34, 7: 49, 8: 49, 
       9: 108, 10: 124, 11: 108, 12: 361, 13: 290, 14: 2118, 15: 5408, 
       16: 43473, 17: 109462, 18: 111490, 19: 244675, 20: 115878, 21: 6960}

count = Counter(dct)
print(count.most_common(3))  # [(19, 244675), (20, 115878), (18, 111490)]
6
jpp 20 nov. 2018 à 10:23

En deux étapes simples:

aux = sorted([(v,k) for (k,v) in dic.items()])
res = [(v,k) for (k,v) in aux[-3:]] 
#[(18, 111490), (20, 115878), (19, 244675)]

Plus rapide que nlargest et Counter.most_common dans cet exemple.

2
B. M. 20 nov. 2018 à 11:35

Cherchez-vous le moyen le plus efficace ou simplement le moyen optimal dans la simplicité permormace / algorithme?

Si c'est le dernier, vous devriez envisager de trier les éléments du dictionnaire sous forme de tuples (vous pouvez les obtenir avec cachedict.items ()) comme dans cette réponse https://stackoverflow.com/a/613218/10453363

Triez simplement les tuples par valeur, puis récupérez les 3 derniers tuples (qui sont des paires clé / valeur)

0
George Bekh-Ivanov 20 nov. 2018 à 10:17

heapq.nlargest

Vous pouvez éviter un tri complet ici en utilisant une file d'attente de tas:

from heapq import nlargest
from operator import itemgetter

dct = {0: 0, 1: 11, 2: 26, 3: 43, 4: 14, 5: 29, 6: 34, 7: 49, 8: 49,
       9: 108, 10: 124, 11: 108, 12: 361, 13: 290, 14: 2118, 15: 5408,
       16: 43473, 17: 109462, 18: 111490, 19: 244675, 20: 115878, 21: 6960}

res = nlargest(3, dct.items(), key=itemgetter(1))

print(res)
# [(19, 244675), (20, 115878), (18, 111490)]
6
jpp 11 janv. 2019 à 09:46

Vous pouvez le faire comme ceci:

dct = {0: 0, 1: 11, 2: 26, 3: 43, 4: 14, 5: 29, 6: 34, 7: 49, 8: 49, 9: 108, 10: 124, 11: 108, 12: 361, 13: 290, 14: 2118, 15: 5408, 16: 43473, 17: 109462, 18: 111490, 19: 244675, 20: 115878, 21: 6960}

res = [next(k for k in dct if dct[k]==v) for v in sorted(dct.values(), reverse=True)[:3]]
print(res)  # -> [19, 20, 18]

Panne:

  • sorted(dct.values(), reverse=True)[:3] :: Prend les 3 valeurs maximales du dictionnaire.
  • next(k for k in dct if dct[k]==v) :: renvoie la clé du dictionnaire, pour laquelle la valeur est l'une des 3 ci-dessus (itérativement).
2
Ev. Kounis 20 nov. 2018 à 10:10

Vous pouvez utiliser ceci:

a = {0: 0, 1: 11, 2: 26, 3: 43, 4: 14, 5: 29, 6: 34, 7: 49, 8: 49,
       9: 108, 10: 124, 11: 108, 12: 361, 13: 290, 14: 2118, 15: 5408,
       16: 43473, 17: 109462, 18: 111490, 19: 244675, 20: 115878, 21: 6960}

l = sorted(list(a.items()), key=lambda tup: tup[1], reverse=True)[:3]
print(l) # [(19, 244675), (20, 115878), (18, 111490)]

Il convertit le dictionnaire a en une liste de tuples, trie par tup[1], l'inverse et obtient les 3 premiers résultats.

3
b-fg 20 nov. 2018 à 10:14

Cela renvoie ce que vous voulez:

d = {0: 0, 1: 11, 2: 26, 3: 43, 4: 14, 5: 29, 6: 34, 7: 49, 8: 49, 9: 108, 10: 124, 11: 108, 12: 361, 13: 290, 14: 2118, 15: 5408, 16: 43473, 17: 109462, 18: 111490, 19: 244675, 20: 115878, 21: 6960}

print(sorted([(i,j) for i, j in d.items() if j in (sorted(d.values())[-3:])])[-3:])
#[(18, 111490), (19, 244675), (20, 115878)]
2
New2coding 20 nov. 2018 à 16:21
d = {0: 0, 1: 11, 2: 26, 3: 43, 4: 14, 5: 29, 6: 34, 7: 49, 8: 49, 9: 108, 10: 124, 11: 108, 12: 361, 13: 290, 14: 2118, 15: 5408, 16: 43473, 17: 109462, 18: 111490, 19: 244675, 20: 115878, 21: 6960}

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

d_items_sorted[:3]

Retour :

[(19, 244675), (20, 115878), (18, 111490)]

C'est le code le plus simple que j'ai pu obtenir, mais le tri du dictionnaire coûte O (nlogn) et vous devriez pouvoir faire de même dans O (n)

1
Corentin Limier 20 nov. 2018 à 10:09