web-dev-qa-db-fra.com

Imprimer les "n" entrées du haut dans un dictionnaire

Voici mon code actuel

pN ={'dave': 10, 'jacinta': 10, 'james': 8, 'john': 6, 'jack': 3, 'sam': 2}
highestCount = max(pN.values())

for k, v in pN.items():
  if v == highestCount:
    print(v,k)

Cependant, cela n'imprime que l'utilisateur principal et, si cette position est partagée, l'imprime à nouveau comme tel.

10 dave
10 jacinta

Je dois pouvoir imprimer n’importe quel nombre d’utilisateurs de premier plan (n) et le formater tel quel, par exemple. pour n = 5:

10 john, jacinta, 
8 james
6 john
3 jack
2 sam
13
user9814201

Utilisez un collections.defaultdict , permutez votre keys et values

from collections import defaultdict
dct = defaultdict(list)

for k, v in pN.items():
  dct[v].append(k)

# defaultdict(<class 'list'>, {10: ['dave', 'jacinta'], 8: ['james'], 6: ['john'], 3: ['jack'], 2: ['sam']})

Utilisez sorted pour la sortie:

for k, v in sorted(dct.items(), reverse=True):
  print(k, ', '.join(v))

# Result

10 dave, jacinta
8 james
6 john
3 jack
2 sam

function pour renvoyer les n premiers utilisateurs (traite les liens comme une entrée):

def top_n(d, n):
  dct = defaultdict(list) 
  for k, v in d.items():
    dct[v].append(k)      
  return sorted(dct.items())[-n:][::-1]

top_n(pN, 3)

# [(10, ['dave', 'jacinta']), (8, ['james']), (6, ['john'])]

Utiliser defaultdict est simple et rapide, et voici quelques exemples pour le prouver:

Fonctions qui seront chronométrées

def chris_z(d, n):
  dct = defaultdict(list) 
  for k, v in d.items():
    dct[v].append(k)      
  return sorted(dct.items())[-n:][::-1]

def tim_lombard(score_dict, n):
  lot = [(k,v) for k, v in score_dict.items()] #make list of Tuple from scores dict
  nl = []
  while len(lot)> 0:
      nl.append(max(lot, key=lambda x: x[1]))
      lot.remove(nl[-1])

def ajax(d, n:'n_users', top = True):
  _ranks = sorted(d.values())
  _ranks = _ranks[-n:] if top else _ranks[:n]
  return {i:[a for a, b in d.items() if b == i] for i in _ranks}

Résultats

x = [''.join(i) for i in itertools.permutations('chrisz', 6)]    
y = [random.randint(0, 100) for _ in range(720)]  
z = dict(Zip(x, y))

In [40]: %timeit chris_z(z, 500)
110 µs ± 259 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [42]: %timeit tim_lombard(z, 500)
26.2 ms ± 60 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [43]: %timeit ajax(z, 500)
15.3 ms ± 227 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
11
user3483203

Est-ce que cela fonctionnerait pour vous? 

pN ={'dave': 10, 'jacinta': 10, 'james': 8, 'john': 6, 'jack': 3, 'sam': 2}

def top_n_scores(n, score_dict):
  ''' returns the n scores from a name:score dict'''
  lot = [(k,v) for k, v in pN.items()] #make list of Tuple from scores dict
  nl = []
  while len(lot)> 0:
      nl.append(max(lot, key=lambda x: x[1]))
      lot.remove(nl[-1])

  return nl[0:n]   

Pour obtenir les 4 meilleurs scores:

top_n_scores(4, pN) 

[('dave', 10), ('jacinta', 10), ('james', 8), ('john', 6)]
1
Timothy Lombard

Vous pouvez utiliser sorted et une compréhension du dictionnaire:

from typing import Dict, List
def ranking(d, n:'n_users', top = True) -> Dict[int, List[str]]:
  _ranks = sorted(d.values())
  _ranks = _ranks[-n:] if top else _ranks[:n]
  return {i:[a for a, b in d.items() if b == i] for i in _ranks}

pN ={'dave': 10, 'jacinta': 10, 'james': 8, 'john': 6, 'jack': 3, 'sam': 2}
for a, b in sorted(ranking(pN, 10).items(), key=lambda x:x[0], reverse=True):
  print('{} {}'.format(a, ', '.join(b)))

Sortie:

10 dave, jacinta
8 james
6 john
3 jack
2 sam

Edit: quel que soit le nombre d'utilisateurs de premier plan, passez la valeur à la fonction

_r = ranking(pN, 5) #for the top 5 users
1
Ajax1234

Vous devriez l'essayer avec collections.defaultdict avec la fonction sorted() intégrée.

from collections import defaultdict

def sort_it(_dict, n):
    result = defaultdict(list)
    for name, num in _dict.items():
        result[num].append(name)
    return sorted(result.items(), reverse=True)[:n]

>>> pN = {'dave': 10, 'jacinta': 10, 'james': 8, 'john': 6, 'jack': 3, 'sam': 2}
>>> top3 = sort_it(pN, 3)
[(10, ['jacinta', 'dave']), (8, ['james']), (6, ['john'])] # Output
0
Bijoy

Puisque vous voulez grouper par scores, il serait logique d’utiliser itertools.groupby :

scores ={'dave': 10, 'jacinta': 10, 'james': 8, 'john': 6, 'jack': 3, 'sam': 2}

from itertools import groupby
from operator import itemgetter

get_score = itemgetter(1)

def group_users_by_score(scores, n=-1):
    sorted_users = sorted(scores.items(), key=get_score, reverse=True)
    top_n = sorted_users[:n]
    return groupby(top_n, key=get_score)

def display_top_users(scores, n=-1):
    for score, users in group_users_by_score(scores, n):
        print("%3d %s" % (score, ', '.join(u for (u,s) in users)))

Par exemple:

>>> display_top_users(scores, 3)
 10 dave, jacinta
  8 james
>>> display_top_users(scores)
 10 dave, jacinta
  8 james
  6 john
  3 jack
0
Eric Duminil