Есть ли какой-нибудь простой вариант распаковки словаря?

#python #dictionary

Вопрос:

Если я сделаю что-то подобное

 some_obj = {"a": 1, "b": 2, "c": 3}
first, *rest = some_obj
 

Я получу список, но я хочу, чтобы он был в 2 словарях: first = {"a": 1} и rest = {"b": 2, "c": 3} . Как я понимаю, я могу создать функцию, но мне интересно, смогу ли я сделать это в одной строке, как в javascript с оператором распространения.

Ответ №1:

Я не знаю, есть ли надежный способ добиться этого в одной строке, но вот один метод.

Сначала распакуйте key s и values ( .items() ). Используя some_obj только итерацию по клавишам.

>>>>>> some_obj = {"a":1, "b":2, "c": 3}
>>>>>> во-первых, *rest = some_obj.>>>элементы()

Но это вернет кортеж,

 >>> first
('a', 1)
>>> rest
[('b', 2), ('c', 3)]
 

Но вы можете снова преобразовать обратно в dict одним dict звонком.

 >>> dict([first])
{'a': 1}
>>> dict(rest)
{'b': 2, 'c': 3}
 

Комментарии:

1. Я думаю, что это самое лучшее, что может быть. Python dict s гарантировал порядок вставки с 3.7, но для этого не так много поддержки методов, как для итераций. Например, вы можете выполнять итерации в порядке вставки, но нет индексации или нарезки. Одна странная вещь заключается OrderedDict в том, что после 3.7 это казалось излишним, но он OrderedDict.popitem может удалить первый или последний элемент, а dict.popitem не может.

Ответ №2:

Один лайнер, вдохновленный Абдулом Ниясом P M’s:

 first, rest = dict([next(i := iter(some_obj.items()))]), dict(i)
 

Использует выражение присваивания, введенное в Python 3.8 почти два года назад.

Ответ №3:

 k = next(iter(some_obj))  # get the first key
first = {k: some_obj.pop(k)}
rest = some_obj
 

Если вам нужно сохранить исходный объект нетронутым — обратите внимание, что это ухудшается с O(1) до O(n) как во времени, так и в пространстве:

 k = next(iter(some_obj))
rest = some_obj.copy()
first = {k: rest.pop(k)}
 

Ответ №4:

Ответ @AbdulNiyasPM совершенно прекрасен, но поскольку вы попросили однострочный, вот один из способов сделать это (хотя сначала вам придется это сделать from operator import itemgetter ):

 first, rest = map(dict, itemgetter(slice(0, 1), slice(1, None))(list(some_obj.items())))
 

Если вы предпочитаете ничего не импортировать, вы можете использовать аналогичную однострочную функцию с lambda функцией, которая принимает один фиксированный аргумент, а остальные в качестве аргументов переменной длины:

 first, rest = map(dict, (lambda f, *r: ((f,), r))(*some_obj.items()))
 

Демо: https://replit.com/@blhsing/ImpeccableEllipticalGeeklog

Комментарии:

1. Извините, пришлось понизить голос — это очень грубо, и вопрос, заданный для «простого варианта» 🙂 Просто потому, что кто-то просит однострочный, не означает, что мы должны потакать ему..