Python. Список к вложенному словарю: странное поведение - PullRequest
0 голосов
/ 02 ноября 2018

Я пользователь Python 3.6. Передо мной стоит простая задача: преобразовать list в dict. Я видел этот полезный вопрос для вдохновения.

Позвольте мне объяснить мою цель: начиная со списка таких объектов:

class AObject():
def __init__(self, sp, sb, n):
    self.superset = sp
    self.subset   = sb
    self.number   = n

Я хочу иметь словарь этого типа: d[superset][subset] = number.

Моя отправная точка - простой список:

s = set((('a','a1'),('a','a2'),('b','b1'),('b','b2'))) #set of tuples
o = [AObject(t[0], t[1], n) for t, n in zip(s, range(0,4))]

чья длина 4.

Теперь я создаю словарь следующим образом:

d = {x.superset: {x.subset : x.number} for x in o}

но

d
Out[5]: {'a': {'a1': 1}, 'b': {'b1': 3}}

Куда делись два других словарных элемента ??

Тот же результат, используя:

d1 = dict(map(lambda x: (x.superset, {x.subset : x.number}), o))

Между тем с циклом for:

from collections import defaultdict
d2 = defaultdict(dict)
for x in o:
    d2[x.superset][x.subset] = x.number

d2
defaultdict(dict, {'a': {'a1': 1, 'a2': 0}, 'b': {'b1': 3, 'b2': 2}})

Мои вопросы:

  • Я думаю, что точно так же происходит обновление словаря, когда я использую dict-понимание, сохраняя только один элемент для каждого superset, как объяснено здесь . Я прав?

  • Как я могу построить свой вложенный словарь питонским способом?

1 Ответ

0 голосов
/ 02 ноября 2018

Ваша проблема здесь:

d = {x.superset: {x.subset : x.number} for x in o}

каждый раз, когда вы получаете новый x.superset, который уже находится в требовании к построению, он переопределяет прежний - он похож на

d2 = { k:v for k,v in [ (1,4),(1,7),(1,9)]} # d2 == {1:9,} - last value to key 1 survives

Тот факт, что вы добавляете один слой больше, не имеет значения - если вы предоставляете несколько одинаковых ключей в dict-comp, вы получаете перезаписывающее поведение, а не update-поведение.

Ваш

from collections import defaultdict
d2 = defaultdict(dict)
for x in o:
    d2[x.superset][x.subset] = x.number

настолько же питонен, насколько это возможно.


Defaultdict-aproach похож (но более эффективен) на:

d2 = {}
for x in o:
    k = d2.setdefault(x.superset,{})
    k[x.subset] = x.number

# {'a': {'a1': 1, 'a2': 0}, 'b': {'b1': 3, 'b2': 2}}

Подход dict comp похож на:

for x in o:
    d2[x.superset] = {x.subset:x.number}

# {'a': {'a1': 1}, 'b': {'b1': 3}}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...