#python #dictionary #nested
#python #словарь #вложенный
Вопрос:
У меня есть вложенный словарь со следующей структурой:
topHitsDict =
{'record301':
{'query': 'OBGP2018240_Oncorhynchus.clarkii',
'hit1':
{'description': 'OBGP-2018-240_Oncorhynchus.clarkii',
'score': '340',
'eval': '2e-94'},
'hit2':
{'description': 'OBGP-2017-332_Oncorhynchus.clarkii',
'score': '340',
'eval': '2e-94'},
'numTopHits': 2},
'record302':
{'query': 'OBGP2018248_Oncorhynchus.kisutch',
'hit1':
{'description': 'OBGP-2018-248_Oncorhynchus.kisutch',
'score': '340',
'eval': '2e-94'},
'hit2':
{'description': 'OBGP-2018-038_Oncorhynchus.kisutch',
'score': '340',
'eval': '2e-94'},
'hit3':
{'description': 'OBGP-2017-271_Oncorhynchus.kisutch',
'score': '340',
'eval': '2e-94'},
'numTopHits': 3},
'record303':
{'query': 'OBGP2019056_Oncorhynchus.tshawytscha',
'hit1':
{'description': 'OBGP-2019-056_Oncorhynchus.tshawytscha',
'score': '340',
'eval': '2e-94'},
'hit2':
{'description': 'OBGP-2017-356_Oncorhynchus.tshawytscha',
'score': '340',
'eval': '2e-94'},
'hit3':
{'description': 'OBGP-2017-052_Oncorhynchus.tshawytscha',
'score': '340',
'eval': '2e-94'},
'numTopHits': 3},
'record304':
{'query': 'OBGP2019190_Oncorhynchus.nerka',
'hit1':
{'description': 'OBGP-2019-191_Oncorhynchus.nerka',
'score': '340',
'eval': '2e-94'},
'hit2':
{'description': 'OBGP-2019-190_Oncorhynchus.nerka',
'score': '340',
'eval': '2e-94'},
'numTopHits': 2}
}
И я хочу получить доступ к ключам «описание» во всех вложенных словарях hitx.
Я знаю, что мог бы использовать циклы for, и я попробовал следующее, думая, что, возможно, я мог бы сократить его до одного цикла for, прокручивая словари recordx, а затем получая доступ ко всем ключам описания в словарях hitx в словаре recordx за один раз, но у меня нет никакого успеха:
hits = dict(filter(lambda item: 'hit' in item[0], topHitsDict['record301'].items()))
seqs = dict(filter(lambda item: 'description' in item[0], hits.items()))
seqs
{}
Любая помощь будет высоко оценена!
Ответ №1:
Я думаю, вы неправильно понимаете, что filter()
делает. Из документации:
filter(function, iterable)
:
Создайте итератор из тех элементов iterable, для которых функция возвращает true .
Поэтому, когда вы делаете
hits = dict(filter(lambda item: 'hit' in item[0], topHitsDict['record301'].items()))
По сути, вы делаете:
hits = {}
for item in topHitsDict['record301'].items():
if 'hit' in item[0]:
hits[item[0]] = item[1]
который дает вам только hit*
ключи от topHitsDict['record301']
.
hits = {'hit1': {'description': 'OBGP-2018-240_Oncorhynchus.clarkii',
'score': '340',
'eval': '2e-94'},
'hit2': {'description': 'OBGP-2017-332_Oncorhynchus.clarkii',
'score': '340',
'eval': '2e-94'}}
Вместо этого вам действительно нужно описание из этих hit*
dicts. Для этого вы можете использовать map
, а затем преобразовать итератор в список.
descriptions = list(map(lambda item: item[1]['description'], hits.items())
# descriptions: ['OBGP-2018-240_Oncorhynchus.clarkii', 'OBGP-2017-332_Oncorhynchus.clarkii']
Это эквивалентно:
descriptions = []
for item in hits.items():
descriptions.append(item[1]['description'])
И если вы хотите сделать это для всех ключей topHitsDict
, вам придется немного изменить его. Либо с помощью цикла:
all_descriptions = []
for recordVal in topHitsDict.values():
hits = dict(filter(lambda item: 'hit' in item[0], recordVal.items()))
descriptions = list(map(lambda item: item[1]['description'], hits.items())
# Add to all_descriptions
all_descriptions = all_descriptions descriptions
Почти всегда проще сначала записать их в виде цикла. Затем вы можете записать их в виде списка или диктовки, а затем использовать и filter()
map()
all_descriptions = []
for record in topHitsDict.values():
for hitname, hitval in record.items():
if "hit" in hitname:
all_descriptions.append(hitval['description'])
Или как понимание:
all_descriptions = [hitval["description"] for record in topHitsDict.values() for hitname, hitval in record.items() if "hit" in hitname]
Ответ №2:
Для выполнения этого вам потребуется 2 цикла, если вы не настаиваете на обработке каждого recordxxx
ключа отдельно, используя 1 цикл.
А также понимание списков немного легче читать / понимать, чем filter
.
desc = [
v["description"]
for _, value in topHitsDict.items()
for k, v in value.items()
if "hit" in k
]
Ответ №3:
Вам нужно сначала перебрать все записи, а затем для каждой записи проверить, является ли значение dict
или нет. Если значение равно dict, выполните поиск description
и добавьте его в список:
description = list()
for key,records in topHitsDict.items():
for inner_key, inner_value in records.items():
if type(inner_value) is dict and "description" in inner_value.keys():
description.append(inner_value['description'])
print(description)
Ответ №4:
Вы могли бы использовать NestedDict
from ndicts.ndicts import NestedDict
all_descriptions = {
'record301': {'hit1': {'description': 'OBGP-2018-240_Oncorhynchus.clarkii',
'eval': '2e-94',
'score': '340'},
'hit2': {'description': 'OBGP-2017-332_Oncorhynchus.clarkii',
'eval': '2e-94',
'score': '340'},
'numTopHits': 2,
'query': 'OBGP2018240_Oncorhynchus.clarkii'},
'record302': {'hit1': {'description': 'OBGP-2018-248_Oncorhynchus.kisutch',
'eval': '2e-94',
'score': '340'},
'hit2': {'description': 'OBGP-2018-038_Oncorhynchus.kisutch',
'eval': '2e-94',
'score': '340'},
'hit3': {'description': 'OBGP-2017-271_Oncorhynchus.kisutch',
'eval': '2e-94',
'score': '340'},
'numTopHits': 3,
'query': 'OBGP2018248_Oncorhynchus.kisutch'}
}
nd = NestedDict(all_descriptions)
nd_description = nd.extract["", "", "description"]
Здесь это результат в виде словаря
>>> nd_description.to_dict()
{'record301': {'hit1': {'description': 'OBGP-2018-240_Oncorhynchus.clarkii'},
'hit2': {'description': 'OBGP-2017-332_Oncorhynchus.clarkii'}},
'record302': {'hit1': {'description': 'OBGP-2018-248_Oncorhynchus.kisutch'},
'hit2': {'description': 'OBGP-2018-038_Oncorhynchus.kisutch'},
'hit3': {'description': 'OBGP-2017-271_Oncorhynchus.kisutch'}},
'record303': {'hit1': {'description': 'OBGP-2019-056_Oncorhynchus.tshawytscha'},
'hit2': {'description': 'OBGP-2017-356_Oncorhynchus.tshawytscha'},
'hit3': {'description': 'OBGP-2017-052_Oncorhynchus.tshawytscha'}},
'record304': {'hit1': {'description': 'OBGP-2019-191_Oncorhynchus.nerka'},
'hit2': {'description': 'OBGP-2019-190_Oncorhynchus.nerka'}}}
Если вам нужны значения
>>> list(nd_description.values())
['OBGP-2018-240_Oncorhynchus.clarkii',
'OBGP-2017-332_Oncorhynchus.clarkii',
...
'OBGP-2019-190_Oncorhynchus.nerka']