Сортировать словарь списков по парам ключ-значение

Я пытаюсь отсортировать значения, которые находятся внутри словаря списков и создать новый список из них. Вот данные:

{
    '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]
}

Я пытаюсь найти 20 самых маленьких значений в них и получить список их соответствующих ключей. Например, первые три наименьших значения: 14 (хиллари), 181 (хиллари) и 229 (фби). Поэтому, как я могу получить такой список:

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

Все значения всегда будут разными. Кроме того, все значения в списке отсортированы по возрастанию и убыванию.

Вот что я попробовал:

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

Это дает мне наименьшее значение, но не любое другое, так как после одной итерации наименьшее значение всегда одинаково. Я думаю, если я смогу удалить это конкретное значение, это будет полезно. Не могу думать ни о чем другом. Спасибо!

Ответы

Ответ 1

Вы можете объединить словарь (здесь d) в список кортежей с соответствующими парами key/value и отсортировать кортежи по значениям:

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')

Ответ 2

Вы могли бы

  1. инвертировать отображение, создав словарь с числами => список имен
  2. сортировать этот словарь (как кортеж)
  3. выбрать 3 первых предмета

как это:

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)

это печатает:

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

обратите внимание, что если к значению привязано несколько имен, этот код выберет только первое (v[0])

Ответ 3

Просто используйте лямбда-функцию в 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]

Ответ 4

Поскольку все значения в списке отсортированы, вы можете использовать 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)]