如何在一行for循环中为字典添加另一个属性

8

我有一个字典列表和一个字符串。我想在列表中的每个字典中添加一个 selected 属性。我想知道是否可能使用一行代码来实现。

以下是我的输入:

saved_fields = "apple|cherry|banana".split('|')
fields = [
    {
        'name' : 'cherry'
    }, 
    {
        'name' : 'apple'
    }, 
    {
        'name' : 'orange'
    }
]

这是我的期望输出:

[
    {
        'name' : 'cherry',
        'selected' : True
    }, 
    {
        'name' : 'apple',
        'selected' : True
    }, 
    {
        'name' : 'orange',
        'selected' : False
    }
]

我尝试了这个:
new_fields = [item [item['selected'] if item['name'] in saved_fields] for item in fields]

你确定你复制代码正确吗?看起来会出现错误。 - kubatucka
1
“我尝试了这个” - 那怎么样了?你得到了什么错误或输出?你尝试如何修复它?有些人(包括我自己)欣赏看到尝试的过程,但真正的重点应该是迭代、分解、调试,也许这会引导你提出不同的问题,或者只是带你找到答案。 - Bernhard Barker
1
你能分多行写吗?从那里开始,然后将其转换为单行可能比直接想出一行要容易得多。虽然“一行内”问题是什么意思?试图将所有内容强制放入一行只会导致代码难以阅读。 - Bernhard Barker
一个“一行循环”是在你的情况下一个字典推导式(或列表推导式,或集合推导式)。请阅读有关字典推导式的内容。 - smci
5个回答

15

我并不一定认为“一行方式”是最好的方式。

s = set(saved_fields)  # set lookup is more efficient 
for d in fields:
    d['status'] = d['name'] in s

fields
# [{'name': 'cherry', 'status': True},
#  {'name': 'apple', 'status': True},
#  {'name': 'orange', 'status': False}]

简单. 明确. 显而易见。

这将对您的字典进行原地更新,如果您有很多记录或其他键,除了“name”和“status”之外,这是更好的选择。我们并不知道这些键的信息。


如果您坚持使用一行代码,则可以使用此代码以保留其他键:

[{**d, 'status': d['name'] in s} for d in fields]  
# [{'name': 'cherry', 'status': True},
#  {'name': 'apple', 'status': True},
#  {'name': 'orange', 'status': False}]

这是 列表推导 语法,它创建了一个新的字典列表,而原始列表保持不变。

必须使用{**d, ...}部分来保留未被修改的键。我没有看到其他答案这样做,所以认为值得一提。

扩展解包语法仅适用于python3.5+版本,对于旧版本,请将{**d,'status': d['name'] in s} 改为 dict(d,**{'status': d['name'] in s})


@smci 不过这不是字典推导式吧?它是一个列表推导式,每次迭代创建一个字典。虽然我的回答的重点是并不总是必须使用它。 - cs95
1
@smci 不是,字典推导式看起来像 {key : value for something in something_else}{**d, 'a': 'b', 'c': 'd'} 只是创建一个字典。 - cs95
1
cs95:不,我没有给它投反对票!别这么多疑,我的朋友。我相信我从来没有在SO上给你的任何优秀内容投过反对票,也许只有一次回答。当然,这个也不是。 - smci
1
第二个答案只是为了满足OP的“一行”要求,就像我说的那样,并不是答案的重点。实际上,我更喜欢它!我非常喜欢它。而且,来自函数式语言的人也会喜欢它。 - smci
@marcelm:好的,但是“从可迭代对象创建的字典是扩展可迭代对象解包和列表推导式的组合”,这肯定需要一些解释,并且对于新的Python用户来说,甚至对其他语言有经验的用户也不容易理解。 - smci
显示剩余8条评论

5
你可以使用选定的键更新 dictionary
for x in fields: x.update({'selected': x['name'] in saved_fields}):

print(fields)

[{'name': 'cherry', 'selected': True}, 
{'name': 'apple', 'selected': True}, 
{'name': 'orange', 'selected': False}]

5
我强烈不建议在列表推导中使用副作用,这是一种众所周知的反模式。你正在生成一个[None, None, None]的结果并将其丢弃。 - cs95
1
好的,根据OP的要求更新为不同的一行代码。 - ScootCork

4
result = [
    {"name": fruit['name'],
     "selected": fruit['name'] in saved_fields } 
    for fruit in fields
]

>>> [{'name': 'cherry', 'selected': True},
 {'name': 'apple', 'selected': True},
 {'name': 'orange', 'selected': False}]

作为一个一行代码:

result = [{"name": fruit['name'], "selected": fruit['name'] in saved_fields} for fruit in fields]

3
建议的解决方案即使在字典中有多个条目也能正常工作。
以您提供的输入为例:
saved_fields = "apple|cherry|banana".split('|')
fields = [
    {
        'name' : 'cherry'
    }, 
    {
        'name' : 'apple'
    }, 
    {
        'name' : 'orange'
    }
]
  1. Using the Dict.update():

    >>> [item.update({'selected': item['name'] in saved_fields}) for item in fields]
    [None, None, None]
    

    Will return [None, None, None] but modifies the fields variable inplace.

    >>> fields
    [{'name': 'cherry', 'selected': True},
     {'name': 'apple', 'selected': True},
     {'name': 'orange', 'selected': False}]
    

    note that while this is a one-liner, this is not always recommended.

  2. If you want a new list without modifying fields. It can be done using ** operator on Dict cf as shown in @cs95 answer. ** explanation:

    >>> new_fields = [{**item, 'selected': item['name'] in saved_fields} for item in fields]
    >>> new_fields
    [{'name': 'cherry', 'selected': True},
     {'name': 'apple', 'selected': True},
     {'name': 'orange', 'selected': False}]
    
    >>> fields
    [{'name': 'cherry'}, {'name': 'apple'}, {'name': 'orange'}]
    

3
仅仅为了产生副作用而使用列表推导式是Python中的反模式。 - Barmar

2
[{'name': item['name'], 'selected': item['name'] in saved_fields} for item in fields]

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