#python #list #dictionary
Вопрос:
У меня есть словарь python
d = {1: 6, 2: 1, 3: 1, 4: 9, 5: 9, 6: 1}
Поскольку значения в приведенном выше словаре не являются уникальными. Я хочу сгруппировать все ключи уникальных значений в виде списка и создать новый словарь следующим образом:
v = {6:[1], 1:[2, 3, 6], 9: [4, 5]}
Обратите внимание, что ключи нового словаря v должны быть отсортированы. Мне трудно визуализировать и реализовать это создание словаря. Пожалуйста, предложите мне простой и эффективный способ сделать это.
Ответ №1:
Использование collections.defaultdict
для удобства:
from collections import defaultdict
v = defaultdict(list)
for key, value in sorted(d.items()):
v[value].append(key)
но вы можете сделать это и с помощью bog-standard dict
, используя dict.setdefault()
:
v = {}
for key, value in sorted(d.items()):
v.setdefault(value, []).append(key)
Приведенное выше правило сначала сортирует ключи; последующая сортировка значений выходного словаря гораздо более громоздка и неэффективна.
Если кому-либо не нужно сортировать выходные данные, вы можете прервать sorted()
вызов и использовать наборы (ключи во входном словаре гарантированно уникальны, поэтому информация не теряется):
v = {}
for key, value in d.items():
v.setdefault(value, set()).add(key)
производить:
{6: {1}, 1: {2, 3, 6}, 9: {4, 5}}
(то, что выходные данные заданных значений сортируются, является совпадением, побочным эффектом того, как реализованы значения хэша для целых чисел; наборы представляют собой неупорядоченные структуры).
Комментарии:
1. Если вы используете defaultdict, но не хотите, чтобы поведение «по умолчанию» продолжалось после инициализации dict, вы можете установить
default_factory
для атрибута значениеNone
. Тогда вашdefaultdict
будет вести себя как обычный dict почти во всех отношениях.2. В качестве примечания, я большой поклонник того, как вы сортируете предметы, а не значения, как это было бы первым инстинктом большинства людей (или, по крайней мере, моим). 1.
3. Что такое
list
во 2-й строке? Кажется, это сработает, просто имеяv = defaultdict()
4. @clwen: нет, это не сработает.
defaultdict()
принимает заводскую функцию , которая при вызове создает новый объект для вставки в словарь, когда ключ еще не существует. Передачаlist
означает, что всякий раз, когда ключ еще не существует,v[value]
объект defaultdict вызываетlist()
и вставляет результат в словарь для этого ключа. Если вы опускаете заводскую функцию,defaultdict
действует как обычный словарь и вызывает aKeyError
для отсутствующих ключей.5. «Сортировка значений выходного словаря позже намного более громоздка и неэффективна». Я придираюсь, но сортировка сгруппированных списков происходит быстрее, чем сортировка всех ключей сначала, говоря асимптотически…
Ответ №2:
Если вам на самом деле не нужен dict
в конце дня, вы можете использовать itertools.groupby
:
from itertools import groupby
from operator import itemgetter
for k, v in groupby(sorted(d.items(), key=itemgetter(1)), itemgetter(1)):
print(k, list(map(itemgetter(0), v)))
Конечно, вы могли бы использовать это для создания dict, если бы вы действительно хотели:
{
k: list(map(itemgetter(0), v))
for k, v in groupby(sorted(d.items(), key=itemgetter(1)), itemgetter(1))
}
Но на этом этапе вам, вероятно, лучше использовать решение Martijn defaultdict.