Фильтровать элементы в словаре python, где ключи содержат определенную строку
Я кодер C, развивающий что-то в python. Я знаю, как сделать следующее в C (и, следовательно, в C-подобной логике, применяемой к python), но мне интересно, как это сделать Python.
У меня есть словарь d, и я хотел бы работать с подмножеством элементов, только те, у кого ключ (строка) содержит определенную подстроку.
то есть. логика C:
for key in d:
if filter_string in key:
# do something
else
# do nothing, continue
Я предполагаю, что версия python будет похожа на
filtered_dict = crazy_python_syntax(d, substring)
for key,value in filtered_dict.iteritems():
# do something
Я нашел много сообщений о фильтрационных словарях, но не смог найти тот, который был именно таким.
Мой словарь не вложен, и я использую python 2.7
Ответы
Ответ 1
Как насчет понятия dict:
filtered_dict = {k:v for k,v in d.iteritems() if filter_string in k}
Как вы видите, он должен быть понятным, поскольку он хорошо читается как английский.
Для этого синтаксиса требуется Python 2.7 или выше.
В Python 3 есть только dict.items()
, а не iteritems()
, поэтому вы должны использовать:
filtered_dict = {k:v for (k,v) in d.items() if filter_string in k}
Ответ 2
Пойдите для того, что является наиболее читаемым и легко ремонтируемым. Просто потому, что вы можете записать его в одной строке, это не значит, что вы должны. Ваше существующее решение близко к тому, что я буду использовать, кроме того, что я бы попросил пользователя пропустить поиск значения, и я ненавижу вложенные ifs, если я могу их избежать:
for key, val in d.iteritems():
if filter_string not in key:
continue
# do something
Однако, если вы realllly хотите что-то позволить вам итерации через фильтрованный dict, то я бы не делал двухэтапный процесс построения отфильтрованного dict, а затем итерации через него, но вместо этого использовал генератор, потому что более pythonic (и удивительный), чем генератор?
Сначала мы создаем наш генератор, и хороший дизайн диктует, что мы делаем его достаточно абстрактным, чтобы его можно было повторно использовать:
# The implementation of my generator may look vaguely familiar, no?
def filter_dict(d, filter_string):
for key, val in d.iteritems():
if filter_string not in key:
continue
yield key, val
И тогда мы сможем использовать генератор, чтобы решить вашу проблему красиво и чисто с помощью простого, понятного кода:
for key, val in filter_dict(d, some_string):
# do something
Короче: генераторы являются удивительными.
Ответ 3
input = {"A":"a", "B":"b", "C":"c"}
output = {k:v for (k,v) in input.items() if key_satifies_condition(k)}
Ответ 4
Джонатан дал вам подход, использующий понимание в его ответ. Вот такой подход, который касается того, что вы что-то делаете.
Если вы хотите что-то сделать со значениями словаря, вам не требуется понимание словаря:
Я использую iteritems(
), так как вы отметили свой вопрос python-2.7
results = map(some_function, [(k,v) for k,v in a_dict.iteritems() if 'foo' in k])
Теперь результат будет в списке с some_function
, примененным к каждой паре ключей/значений словаря, который имеет foo
в своем ключе.
Если вы просто хотите иметь дело со значениями и игнорировать ключи, просто измените понимание списка:
results = map(some_function, [v for k,v in a_dict.iteritems() if 'foo' in k])
some_function
может быть любым вызываемым, поэтому работала бы лямбда:
results = map(lambda x: x*2, [v for k,v in a_dict.iteritems() if 'foo' in k])
Внутренний список на самом деле не требуется, поскольку вы также можете передать выражение генератора для отображения:
>>> map(lambda a: a[0]*a[1], ((k,v) for k,v in {2:2, 3:2}.iteritems() if k == 2))
[4]