озадачен получением ключевого значения от понимания

Я пытаюсь понять, как получить значения из понимания, которое почти работает. Из этих данных..

{'rock': {}, 'coal1': {'gold1': {'data': ['g1']}}, 'coal2': {'gold3': {'data': ['g3']}, 'gold2': {'data': ['g2']}}}

.. я пытаюсь извлечь данные золотого ключа в простой диктофон. т. е. набор из { gold : {'data' : [...]} } элементов, по существу вырывающих угольные ключи из данных.

другими словами отсюда..

{
  "coal2": {
    "gold3": {
      "data": [
        "g3"
      ]
    },
    "gold2": {
      "data": [
        "g2"
      ]
    }
  },
  "coal1": {
    "gold1": {
      "data": [
        "g1"
      ]
    }
  },
  "rock": {}
}

к этому формату

{
  "gold3": {
    "data": [
      "g3"
    ]
  },
  "gold1": {
    "data": [
      "g1"
    ]
  },
  "gold2": {
    "data": [
      "g2"
    ]
  }
}

Это почти работает. Это избавит от камня.

>>> {k:d for k,d in data.items() if k != 'rock'}
{'coal2': {'gold3': {'data': ['g3']}, 'gold2': {'data': ['g2']}}, 'coal1': {'gold1': {'data': ['g1']}}}

И получение значений избавляет от угольных ключей.

>>> [v for v in {k:d for k,d in data.items() if k != 'rock'}.values()]
[{'gold3': {'data': ['g3']}, 'gold2': {'data': ['g2']}}, {'gold1': {'data': ['g1']}}]

Но я не могу понять, как получить от этого

>>> for i in [v for v in {k:d for k,d in data.items() if k != 'rock'}.values()] : print(i)
...
{'gold3': {'data': ['g3']}, 'gold2': {'data': ['g2']}}
{'gold1': {'data': ['g1']}}

до желаемой структуры. И было бы мило, если бы все это можно было сделать с пониманием. Кто-нибудь знает, как это сделать?

РЕДАКТИРОВАТЬ: Оба ответа были потрясающими, и я хотел бы принять оба. Мне нравится ничего не импортировать, но я принимаю версию @blhsing itertools только потому, что ее легче понять и она немного лучше работает. Кстати, рок должен быть отброшен, даже если он имеет ценность, поэтому я не мог обойти if k != 'rock'. Итак, вот результаты и... Спасибо, ребята.

>>> import timeit
>>> data = {'rock': {'type':'pebble'}, 'coal1': {'gold1': {'data': ['g1']}}, 'coal2': {'gold3': {'data': ['g3']}, 'gold2': {'data': ['g2']}}}
>>> timeit.timeit( "dict(kv for x in (v for v in {k:d for k,d in data.items() if k != 'rock'}.values()) for kv in x.items())" ,  setup="from __main__ import data")            
2.6714617270044982
>>>
>>> timeit.timeit( "dict(chain.from_iterable(g.items() for g in {k:d for k,d in data.items() if k != 'rock'}.values()))" , setup="from __main__ import data; from itertools import chain")
2.22612579818815
>>>

person Peter Moore    schedule 22.03.2019    source источник


Ответы (2)


Вы можете использовать выражение генератора, которое выводит элементы подзаголовков значений основного словаря и использовать itertools.chain.from_iterable для объединения элементов и передачи их конструктору dict:

from itertools import chain
dict(chain.from_iterable(g.items() for g in d.values()))

так что дано:

d = {'rock': {}, 'coal1': {'gold1': {'data': ['g1']}}, 'coal2': {'gold3': {'data': ['g3']}, 'gold2': {'data': ['g2']}}}

это возвращает:

{'gold3': {'data': ['g3']}, 'gold2': {'data': ['g2']}, 'gold1': {'data': ['g1']}}
person blhsing    schedule 22.03.2019

Просто нужно сделать ваш list из dict до dict (исправление вашего кода с добавлением второй строки)

l=[v for v in {k:d for k,d in d.items() if k != 'rock'}.values()] # here is your own code 
newd=dict(kv for x in l for kv in x.items())
newd
Out[431]: 
{'gold1': {'data': ['g1']},
 'gold2': {'data': ['g2']},
 'gold3': {'data': ['g3']}}

с одной линией

dict(v for d in d.values() for v in d.items()) # d is your dict
Out[436]: 
{'gold1': {'data': ['g1']},
 'gold2': {'data': ['g2']},
 'gold3': {'data': ['g3']}}
person BENY    schedule 22.03.2019
comment
о, и еще одна перефразировка этого решения, чтобы попытаться сделать его быстрее, к моему удивлению, все еще медленнее, чем версия itertools. >>> timeit.timeit( "dict(v for d in data.values() for v in data.items() if v[0] != 'rock')" , setup="from __main__ import data") 2,7223397847265005 - person Peter Moore; 22.03.2019