我如何在字典推导中使用if/else条件语句?

245

在Python 2.7+中是否存在一种类似下面的实现方式?

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

我知道你可以只用“if”语句实现任何东西:

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

4
ж №жҚ® @Marcin зҡ„и®Іиҝ°пјҢdict з”ұ key:value е…ғзҙ з»„жҲҗпјҢдҪ еңЁиҝҷйҮҢдёҚжҳҜеңЁжһ„е»әдёҖдёӘ dict иҖҢжҳҜдёҖдёӘ set пјҲеҸӮи§Ғ set еӯ—йқўйҮҸпјүгҖӮ - mdeous
5个回答

433

您已经拥有它了:A if test else B 是一个有效的Python表达式。您字典推导式中唯一的问题是,字典推导式中表达式所在的位置必须有两个表达式,用冒号分隔:

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

最后的if从句充当了过滤器的作用,这与条件表达式是不同的。


69
值得一提的是,你不需要为键和值都设置if-else条件语句。例如,{(如果条件成立则为a否则为b):键值对中的值} for 键,键值对中的值 in 字典.items() 就可以达到相同的效果。 - Jeremy Weirich
7
如果你不想的话,针对它们你不需要写if-else语句。 - Marcin
1
@Marcin,我能否只使用“if”作为关键部分,并在值部分同时使用“if”和“else”? - Stan11
表达式周围的括号不是必需的(虽然确实推荐使用)。 - Jeyekomon

21

@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'}}

对于您使用 d1d2 的第二个示例,我收到了 AttributeError: 'dict_values' object has no attribute 'index' 错误。 - alancalvitti
@alancalvitti:感谢您指出这一点!该解决方案适用于Python 2,而不适用于Python 3;我也添加了一个Python 3的解决方案。 - Cleb

9

如果您需要对键和值进行不同的条件评估,@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'}}

假设您只想在其值中使用a后缀keys,并且您希望在这种情况下将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'}}

5
也值得一提的是,只有语句会将if放在结尾:
{_ for _ in iterable if True}

2
很好,这正是我在寻找的。可惜没有一种像 Python 风格那样保持语法相同的方法,然后只需执行类似于 else pass 的操作。 - physincubus

2

在字典推导中使用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}}”

最后,使用一行字典推导式语句:
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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接