0

I want to be able to print the top three values in a dictionary created in another function, where there may be repeating values.

For example, if I have a dictionary d = { a:1, b:2, c:3, d:3, e:4 } I would only want a, b, and c returned.

This is what I currently have, but the output would be a, b, c, d. I don't want to remove d from the dictionary, I just don't want it returned when I run this function.

def top3(filename: str):
    """
    Takes dict defined in wd_inventory, identifies top 3 words in dict
    :param filename:
    :return:
    """
    d = max_frequency(filename)
    x = list(d.values())
    x.sort(reverse=True)
    y = set(x)
    x = x[0:3]
    for i in x:
        for j in d.keys():
            if d[j] == i:
                print(str(j) + " : " + str(d[j]))
    return
wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • 1
    I would like it to return the keys with the three highest values. The problem I'm having is that if there are keys with duplicate values, my code will return more than 3 k : v pairs. I only want it to return a maximum of 3 k : v pairs. I would like it to return the first one that comes up chronologically in the dictionary. – E.Mena14 Sep 11 '22 at 19:46
  • @E.Mena14 *"the keys with the three highest values"* -- Shouldn't that be "lowest values"? – wjandrea Sep 11 '22 at 19:49
  • What you are asking for is impossible, as is. Even though it may seem to you that a dictionary is ordered, it is actually not. This means that, when you iterate over its elements, they may come up in *any* order. You should use a data structure that fits your issue better, such as an `OrderedDict`. – jthulhu Sep 11 '22 at 19:50
  • 1
    @BlackBeans That's incorrect. [Dictionaries preserve insertion order as of Python 3.7.](/a/39980744/4518341) – wjandrea Sep 11 '22 at 19:51
  • @wjandrea indeed. – jthulhu Sep 11 '22 at 19:53
  • @BlackBeans You might as well delete your comment then – wjandrea Sep 11 '22 at 20:30
  • @wjandrea no, because the OP (or, really, anyone else reading this question) might use a previous version of Python 3 than 3.7. Besides, deleting wrong comments is not useful as anyone else who didn't know that will comment it again: I feel it's more useful to leave errors too in plain sight (if labeled as such, which you did). – jthulhu Sep 12 '22 at 20:36

3 Answers3

1

One solution could be the following:

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

print(sorted(d.items(), key=lambda x: x[1])[:3])

OUTPUT

[('e', 1), ('c', 2), ('a', 3)]

Note that will return truly the top 3 entry (by value), not the ones with keys 1, 2 and 3.

EDIT

I don't know what repeating value means exactly, but let's assume that in a dictionary like:

d = {"a":1, "b": 2, "c": 3, "d": 1, "e": 1}

You would like to print just a, b and c (given that d and e repeat the same value as a)

You could use the following approach:

from collections import defaultdict

res = defaultdict(list)
for key, val in sorted(d.items()):
    res[val].append(key)
    
print([y[0] for x, y in list(res.items())])

OUTPUT

['a', 'b', 'c']
nikeros
  • 3,302
  • 2
  • 10
  • 26
0

You can use heapq.nsmallest() to get the n smallest values in an iterable. This might be especially useful if the dict is very large, because it saves sorting a whole list only to select just three elements of it.

from heapq import nsmallest
from operator import itemgetter

def top3(dct):
    return nsmallest(3, dct.items(), key=itemgetter(1))

dct = {'a':1, 'b':2, 'c':3, 'd':3, 'e':4}
for k, v in top3(dct):
    print(f"{k}: {v}")

Output

a: 1
b: 2
c: 3

Due credit: I copied parts of j1-lee's code to use as a template.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
-1

[edited]

sorry, i have overseen that the smallest number has the highest status.

the code now is sorting the dictionary. this creates a list of tuples.

dic = {'aaa':3, 'xxx':1, 'ccc':8, 'yyy': 4, 'kkk':12}
res = sorted(dic.items(), key=lambda x: x[1])
print(res[:3])

result is:

[('xxx', 1), ('aaa', 3), ('yyy', 4)]
lroth
  • 367
  • 1
  • 2
  • 4
  • 1
    OP wants the items with the *smallest* values. They seem to be using a system where lower numbers mean a higher rank, or something like that. – wjandrea Sep 11 '22 at 20:28
  • i have edited my code so that the expected result can be reached – lroth Sep 11 '22 at 21:17
  • That's better, but [nikeros's answer](/a/73682279/4518341) already covers this technique. There's no point having a duplicate answer. – wjandrea Sep 11 '22 at 21:19
  • There's also no reason to have edit notes. It's best to present your solution as fully-formed. But where you totally changed your solution, it'd be better to delete it. And if it weren't a duplicate solution, then I'd say to post a new answer, but it's not, so might as well just delete it outright. – wjandrea Sep 11 '22 at 21:23