Python 3.6使用带有lambda的filter()迭代字典列表不会返回字典的值

Vla*_*lad 0 python dictionary list filter

有一个字典列表我需要迭代并过滤符合条件的字典,然后只返回key1下的值.我正在使用过滤器,如下所示:

res = list(filter(lambda x: x["key1"] if ["key2"] == criterion else False, list_of_dicts))
Run Code Online (Sandbox Code Playgroud)

迭代器可以正常返回那些符合标准的结果.但它返回整个字典而不仅仅是x["key1"].我认为它与过滤器有关但却没有任何线索.

Q1:有人可以解释为什么它返回整个dict而不是key1下的值吗?

Q2:是否有一种解决方法使过滤器只返回key1下的值?

PS通过列表理解这样做是没有问题的:

res = [i["key1"] for i in list_of_dicts if i["key2"] == criterion]
Run Code Online (Sandbox Code Playgroud)

但我只是好奇为什么过滤器不会返回i["key1"].

Mar*_*ers 7

过滤与映射不同.过滤根据您的标准选择,是/否决定是否包含您的一个值.

事实上,你正在过滤两者key2 和真值key1 ; 如果值的值key1被设置为None或者是0另一个假值,那么你也会删除那个我认为你不想要的特定字典.

您想要过滤和映射,因此从通过过滤器的字典中提取正确的密钥.这实际上最好用列表理解来完成:

res = [x["key1"] for x in list_of_dicts if ["key2"] == criterion]
Run Code Online (Sandbox Code Playgroud)

filter()如果必须的话,你仍然可以使用它,但是你需要添加一个map()调用来实际进行映射:

res = list(map(lambda x: x["key1"], filter(lambda x: ["key2"], list_of_dicts)))
Run Code Online (Sandbox Code Playgroud)

但正如你所注意到的那样,这很快就会变得冗长和不可读.您可以使用operator.itemgetter()对象来替换lambdas:

from operator import itemgetter

res = list(map(itemgetter("key1"), filter(lambda d: d["key2"] == condition, list_of_dicts)))
Run Code Online (Sandbox Code Playgroud)

但可读性并没有太大提高.

  • @new_to_coding:它更快,因为列表推导循环完全作为字节码解释步骤执行,包括过滤器测试和提取表达式.这里是`itemgetter()`和`map()`和`filter()`的组合,它是真正的速度恶魔,*所有的执行*完全在C代码中完成,在解释器循环之外. (2认同)
  • @new_to_coding:我确实犯了一个错误; 过滤器必须测试与条件的相等性,此时性能提升会减弱. (2认同)

Wil*_*sem 6

过滤器只是过滤:它将可迭代的输入作为输入,并生成与满足标准的项目的可互换性.

你想要的是一个额外的mapping:

from operator import itemgetter

key1 = itemgetter('key1')

res = list(map(key1,filter(lambda x: ["key2"] == criterion, list_of_dicts)))
Run Code Online (Sandbox Code Playgroud)

请注意,您不需要x['key1'] if ... else False在标准中使用:filter(..)将简单地评估函数,并检查结果的真实性.如果是True,它将发出该项目,否则它将忽略该项目.