Понимание словаря Python

386

Можно ли создать словарь понимания на Python (для ключей)?

Без понимания списка вы можете использовать что-то вроде этого:

l = []
for n in range(1, 11):
    l.append(n)

Мы можем сократить это до понимания списка l = [n for n in range(1, 11)].

Однако, скажем, я хочу установить ключи словаря на то же значение. Я могу сделать:

d = {}
for n in range(1, 11):
     d[n] = True # same value for each

Я пробовал это:

d = {}
d[i for i in range(1, 11)] = True

Тем не менее, я получаю SyntaxErrorна for.

Кроме того (мне не нужна эта часть, но мне просто интересно), вы можете установить ключи словаря для набора различных значений, например так:

d = {}
for n in range(1, 11):
    d[n] = n

Возможно ли это при понимании словаря?

d = {}
d[i for i in range(1, 11)] = [x for x in range(1, 11)]

Это также поднимает SyntaxErrorна for.

Rushy Panchal
источник
3
Информация для будущих читателей: массивы NumPy позволяют задавать для нескольких элементов одно значение или список значений, как вы пытаетесь это сделать. Хотя, если у вас еще нет причин использовать NumPy, вероятно, это не стоит того, чтобы использовать эту функцию.
Дэвид Z

Ответы:

520

Есть словарь в Python 2.7+ , но они работают не так, как вы. Подобно пониманию списка, они создают новый словарь; Вы не можете использовать их для добавления ключей в существующий словарь. Кроме того, вы должны указать ключи и значения, хотя, конечно, вы можете указать фиктивное значение, если хотите.

>>> d = {n: n**2 for n in range(5)}
>>> print d
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

Если вы хотите установить их все в True:

>>> d = {n: True for n in range(5)}
>>> print d
{0: True, 1: True, 2: True, 3: True, 4: True}

То, что вы, кажется, просите, это способ установить несколько ключей одновременно в существующем словаре. Там нет прямого ярлыка для этого. Вы можете либо зациклить, как вы уже показали, или вы можете использовать словарное понимание, чтобы создать новый dict с новыми значениями, а затем сделать, oldDict.update(newDict)чтобы объединить новые значения в старый dict.

BrenBarn
источник
15
FWIW, dict.updateтакже может принимать итерируемые пары ключ-значение, как dictконструктор
mgilson
6
Обратите внимание, что если вы хотите создать словарь со всеми одинаковыми значениями, используйте dict.fromkeys(). Таким образом, чтобы установить все значения True, используйте dict.fromkeys(range(5), True). Обратите внимание, что значение не копируется , поэтому вы можете избежать этого, когда у вас есть изменяемое значение; это будет разделено между всеми ключами.
Мартин Питерс
2
Примечание: клавиши могут быть результатом метода , а также: { n*2 : n for n in range(3) } => {0: 0, 2: 1, 4: 2}. Как можно сделать в одном выражении: { n*2 : n*3 for n in range(3) } => { 0: 0, 2: 3, 4: 6 }.
Zaaier
151

Вы можете использовать dict.fromkeysметод класса ...

>>> dict.fromkeys(range(5), True)
{0: True, 1: True, 2: True, 3: True, 4: True}

Это самый быстрый способ создать словарь, в котором все ключи соответствуют одному значению.

Но ничего не использовать это с изменяемыми объектами :

d = dict.fromkeys(range(5), [])
# {0: [], 1: [], 2: [], 3: [], 4: []}
d[1].append(2)
# {0: [2], 1: [2], 2: [2], 3: [2], 4: [2]} !!!

Если вам на самом деле не нужно инициализировать все ключи, defaultdictможет быть также полезен a :

from collections import defaultdict
d = defaultdict(True)

Чтобы ответить на вторую часть, вам нужно именно это понимание:

{k: k for k in range(10)}

Вы, вероятно, не должны этого делать, но вы также можете создать подкласс, dictкоторый работает как a, defaultdictесли вы переопределите __missing__:

>>> class KeyDict(dict):
...    def __missing__(self, key):
...       #self[key] = key  # Maybe add this also?
...       return key
... 
>>> d = KeyDict()
>>> d[1]
1
>>> d[2]
2
>>> d[3]
3
>>> print(d)
{}
mgilson
источник
Обратите внимание, что в случае d = defaultdict(lambda: True), лямбда не требуется, так как True является (или не должен) быть изменяемым.
rhbvkleef
28
>>> {i:i for i in range(1, 11)}
{1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10}
NPE
источник
22

Мне очень нравится комментарий @mgilson, так как если у вас есть две итерируемые, одна из которых соответствует ключам, а другая значения, вы также можете сделать следующее.

keys = ['a', 'b', 'c']
values = [1, 2, 3]
d = dict(zip(keys, values))

дающий

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

ehontz
источник
4
Используя понимание Dict:{i:j for i in keys for j in values}
LoMaPh
11

Используйте dict () в списке кортежей, это решение позволит вам иметь произвольные значения в каждом списке, если они имеют одинаковую длину

i_s = range(1, 11)
x_s = range(1, 11)
# x_s = range(11, 1, -1) # Also works
d = dict([(i_s[index], x_s[index], ) for index in range(len(i_s))])
Bryan
источник
12
В качестве примечания, это то же самое, что иd = dict(zip(i_s,x_s))
mgilson
10

Рассмотрим этот пример подсчета появления слов в списке с использованием словарного понимания.

my_list = ['hello', 'hi', 'hello', 'today', 'morning', 'again', 'hello']
my_dict = {k:my_list.count(k) for k in my_list}
print(my_dict)

И результат

{'again': 1, 'hi': 1, 'hello': 3, 'today': 1, 'morning': 1}
adonese
источник
Это интересно, хотя и не самым эффективным, так как вы будете подсчитывать такие ключи, как «привет» несколько раз
FuriousGeorge
7

Основной целью понимания списка является создание нового списка на основе другого без изменения или уничтожения исходного списка.

Вместо того чтобы писать

    l = []
    for n in range(1, 11):
        l.append(n)

или

    l = [n for n in range(1, 11)]

ты должен писать только

    l = range(1, 11)

В двух верхних блоках кода вы создаете новый список, просматриваете его и просто возвращаете каждый элемент. Это просто дорогой способ создания копии списка.

Чтобы получить новый словарь со всеми ключами, установленными на одно и то же значение, на основе другого dict, сделайте следующее:

    old_dict = {'a': 1, 'c': 3, 'b': 2}
    new_dict = { key:'your value here' for key in old_dict.keys()}

Вы получаете SyntaxError, потому что когда вы пишете

    d = {}
    d[i for i in range(1, 11)] = True

Вы в основном говорите: «Установите мой ключ« i для i в диапазоне (1, 11) »в значение« Истина », а« i для i в диапазоне (1, 11) »не является допустимым ключом, это просто синтаксическая ошибка. Если dicts поддерживает списки в качестве ключей, вы должны сделать что-то вроде

    d[[i for i in range(1, 11)]] = True

и не

    d[i for i in range(1, 11)] = True

но списки не являются хэшируемыми, поэтому вы не можете использовать их в качестве ключей dict.

Bonifacio2
источник
-3

Вы не можете хешировать такой список. попробуйте вместо этого, он использует кортежи

d[tuple([i for i in range(1,11)])] = True
Адитья Сихаг
источник