17

I am trying to sort values that are inside a dictionary of lists and create a new list out of them. Here is the data:

{
    'fbi': [229, 421, 586, 654, 947, 955, 1095, 1294, 1467, 2423, 3063, 3478, 3617, 3730, 3848, 3959, 4018, 4136, 4297, 4435, 4635, 4679, 4738, 5116, 5211, 5330, 5698, 6107, 6792, 6906, 7036], 
    'comey': [605, 756, 1388, 1439, 1593, 1810, 1959, 2123, 2506, 3037, 6848], 
    'hillary': [14, 181, 449, 614, 704, 1079, 1250, 2484, 2534, 2659, 3233, 3374, 3488, 3565, 4076, 4756, 4865, 6125, 7109]
}

What I am trying is to find the 20 smallest values in these and get a list of their corresponding keys. For example, the first three least values are 14(hillary), 181(hillary) and 229(fbi). Therefore, how can I get a list like this:

['hillary', 'hillary', 'fbi']

All values will always be different. Also, all the values in the list are sorted, from ascending to descending.

Here is what I have tried:

for m in range(1,20):
    for i in sort_vals.values():
        if i[0] < a[0]:
            a[0] = i[0]

This gives me the least value but not any other as after one iteration, the least value is always the same. I guess if I can delete that particular value it will be helpful. Can't think of anything else. Thanks!

4 Answers 4

17

You could flatten the dictionary (d here) into a list of tuples with the corresponding key/value pairs, and sort the tuples according to the values:

from operator import itemgetter

l = [(k,i) for k,v in d.items() for i in v]
# [('fbi', 229), ('fbi', 421), ('fbi', 586), ('fbi', 654),...
list(zip(*sorted(l, key=itemgetter(1))[:3]))[0]
# ('hillary', 'hillary', 'fbi')
Sign up to request clarification or add additional context in comments.

Comments

12

you could

  1. invert your mapping, creating a dictionary with numbers => list of names
  2. sort this dictionary (as tuple)
  3. pick the 3 first items

like this:

import collections

d = collections.defaultdict(list)
data = {'fbi': [229, 421, 586, 654, 947, 955, 1095, 1294, 1467, 2423, 3063, 3478, 3617, 3730, 3848, 3959, 4018, 4136, 4297, 4435, 4635, 4679, 4738, 5116, 5211, 5330, 5698, 6107, 6792, 6906, 7036], 'comey': [605, 756, 1388, 1439, 1593, 1810, 1959, 2123, 2506, 3037, 6848], 'hillary': [14, 181, 449, 614, 704, 1079, 1250, 2484, 2534, 2659, 3233, 3374, 3488, 3565, 4076, 4756, 4865, 6125, 7109]}

for k,vlist in data.items():
    for v in vlist:
        d[v].append(k)

result = [v[0] for k,v in sorted(d.items())[:3]]

print(result)

this prints:

['hillary', 'hillary', 'fbi']

note that if there are several names attached to a value, this code will pick only the first one (v[0])

2 Comments

Hopefully a number is only in one list
Image
in that case it will work. but I wanted to outline the other case.
3

Just use lambda function in sorted().

l = [(k,i) for k,v in d.items() for i in v]
res = [v[0] for v in sorted(l, key=lambda x: x[1])][:20]

Comments

0

Since all the values in the list are sorted, you can use heapq.merge:

d = {
    'fbi': [229, 421, 586, 654, 947, 955, 1095, 1294, 1467, 2423, 3063, 3478, 3617, 3730, 3848, 3959, 4018, 4136, 4297, 4435, 4635, 4679, 4738, 5116, 5211, 5330, 5698, 6107, 6792, 6906, 7036], 
    'comey': [605, 756, 1388, 1439, 1593, 1810, 1959, 2123, 2506, 3037, 6848], 
    'hillary': [14, 181, 449, 614, 704, 1079, 1250, 2484, 2534, 2659, 3233, 3374, 3488, 3565, 4076, 4756, 4865, 6125, 7109]
}
import heapq
pairs = [[(k, i) for i in v] for k, v in d.items()]
sorted_pairs = heapq.merge(*pairs, key=lambda a: a[1])
smallest_num_you_want = 3
res = [next(sorted_pairs)[0] for i in range(smallest_num_you_want)]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.