Как я могу использовать if / else в понимании словаря?

Есть ли в Python 2.7+ способ сделать что-то вроде следующего?

{ something_if_true if condition else something_if_false for key, value in dict_.items() }

Я знаю, что вы можете сделать все, что угодно, просто «если»:

{ something_if_true for key, value in dict_.items() if condition}

person diegueus9    schedule 25.02.2012    source источник
comment
как сказал @Marcin, dict состоит из key:value элементов, здесь вы строите не dict, а set (см. установить литералы).   -  person mdeous    schedule 25.02.2012


Ответы (5)


У вас уже есть это: A if test else B - допустимое выражение Python. Единственная проблема с вашим пониманием dict, как показано, заключается в том, что место для выражения в понимании dict должно иметь два выражения, разделенных двоеточием:

{ (some_key if condition else default_key):(something_if_true if condition
          else something_if_false) for key, value in dict_.items() }

Последнее предложение if действует как фильтр, который отличается от условного выражения.

person Marcin    schedule 25.02.2012
comment
Стоит упомянуть, что вам не нужно иметь условие if-else как для ключа, так и для значения. Например, {(a if condition else b): value for key, value in dict.items()} будет работать. - person Jeremy Weirich; 26.07.2016
comment
@JeremyWeirich Вам не нужно иметь if-else для любого из них, если вы не хотите. - person Marcin; 26.07.2016
comment
@Marcin Могу ли я использовать только if для ключевой части и использовать как if, так и else для части значения? - person nithin11; 12.06.2020
comment
Скобки вокруг выражения не обязательны (хотя это действительно рекомендуется). - person Jeyekomon; 28.06.2021

Ответ @ Marcin охватывает все это, но на случай, если кто-то захочет увидеть реальный пример, я добавлю два ниже:

Допустим, у вас есть следующий словарь множеств

d = {'key1': {'a', 'b', 'c'}, 'key2': {'foo', 'bar'}, 'key3': {'so', 'sad'}}

и вы хотите создать новый словарь, ключи которого указывают, содержится ли строка 'a' в значениях или нет, вы можете использовать

dout = {"a_in_values_of_{}".format(k) if 'a' in v else "a_not_in_values_of_{}".format(k): v for k, v in d.items()}

что дает

{'a_in_values_of_key1': {'a', 'b', 'c'},
 'a_not_in_values_of_key2': {'bar', 'foo'},
 'a_not_in_values_of_key3': {'sad', 'so'}}

Теперь предположим, что у вас есть два таких словаря

d1 = {'bad_key1': {'a', 'b', 'c'}, 'bad_key2': {'foo', 'bar'}, 'bad_key3': {'so', 'sad'}}
d2 = {'good_key1': {'foo', 'bar', 'xyz'}, 'good_key2': {'a', 'b', 'c'}}

и вы хотите заменить ключи в d1 ключами d2, если соответствующие значения идентичны, вы можете сделать

# here we assume that the values in d2 are unique
# Python 2
dout2 = {d2.keys()[d2.values().index(v1)] if v1 in d2.values() else k1: v1 for k1, v1 in d1.items()}

# Python 3
dout2 = {list(d2.keys())[list(d2.values()).index(v1)] if v1 in d2.values() else k1: v1 for k1, v1 in d1.items()}

который дает

{'bad_key2': {'bar', 'foo'},
 'bad_key3': {'sad', 'so'},
 'good_key2': {'a', 'b', 'c'}}
person Cleb    schedule 14.11.2017
comment
для вашего второго примера с использованием d1, d2 я получаю AttributeError: 'dict_values' object has no attribute 'index' - person alancalvitti; 22.02.2019
comment
@alancalvitti: спасибо, что указали на это! Решение было для Python 2 и не работает для Python 3; Я также добавил решение Python 3. - person Cleb; 23.02.2019

Если у вас есть разные условия для оценки ключей и значений, ответ @Marcin - правильный выбор.

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

dict((modify_k(k), modify_v(v)) if condition else (k, v) for k, v in dct.items())

Его легче читать, и условие оценивается только один раз для каждого ключа, значения.

Пример с заимствованием словаря множеств @ Cleb:

d = {'key1': {'a', 'b', 'c'}, 'key2': {'foo', 'bar'}, 'key3': {'so', 'sad'}}

Предположим, вы хотите добавить суффикс только keys с a в его value, и вы хотите, чтобы value заменили длиной набора в таком случае. В противном случае пара "ключ-значение" не должна измениться.

dict((f"{k}_a", len(v)) if "a" in v else (k, v) for k, v in d.items())
# {'key1_a': 3, 'key2': {'bar', 'foo'}, 'key3': {'sad', 'so'}}
person Darkonaut    schedule 23.01.2020

Также стоит упомянуть, что операторы If only помещают if в конец:

{_ for _ in iterable if True}
person Gavin Ray    schedule 25.05.2021

Другой пример использования if / else в понимании словаря

Я работаю над настольным приложением для ввода данных для своей собственной офисной работы, и такое приложение для ввода данных обычно получает все записи из виджета ввода и выгружает их в словарь для дальнейшей обработки, такой как проверка или редактирование, которые мы должны вернуть. выбранные данные из файла обратно в виджеты ввода и т. д.

Первый раунд с использованием традиционной кодировки (8 строк):

entries = {'name': 'Material Name', 'maxt': 'Max Working Temperature', 'ther': {100: 1.1, 200: 1.2}}

a_dic, b_dic = {}, {}

for field, value in entries.items():
    if field == 'ther':
        for k,v in value.items():
            b_dic[k] = v
        a_dic[field] = b_dic
    else:
        a_dic[field] = value
    
print(a_dic)
“ {'name': 'Material Name', 'maxt': 'Max Working Temperature', 'ther': {100: 1.1, 200: 1.2}}”

Во втором раунде я попытался использовать понимание словаря, но цикл все еще существует (6 строк):

entries = {'name': 'Material Name', 'maxt': 'Max Working Temperature', 'ther': {100: 1.1, 200: 1.2}}

for field, value in entries.items():
    if field == 'ther':
        b_dic = {k:v for k,v in value.items()}
        a_dic[field] = b_dic
    else:
        a_dic[field] = value
    
print(a_dic)
“ {'name': 'Material Name', 'maxt': 'Max Working Temperature', 'ther': {100: 1.1, 200: 1.2}}”

Наконец, с помощью однострочного оператора понимания словаря (1 строка):

entries = {'name': 'Material Name', 'maxt': 'Max Working Temperature', 'ther': {100: 1.1, 200: 1.2}}

a_dic = {field:{k:v for k,v in value.items()} if field == 'ther' 
        else value for field, value in entries.items()}
    
print(a_dic)
“ {'name': 'Material Name', 'maxt': 'Max Working Temperature', 'ther': {100: 1.1, 200: 1.2}}”

Я использую python 3.8.3

person KokoEfraim    schedule 24.07.2020