lambda和Dict.items()上的奇怪行为



我正试图用以下代码替换字符串中的重复单词:

from functools import reduce
from collections import Counter
import re

if __name__ == '__main__':
sentence = 'User Key Account Department Account Start Date'
result = reduce(
lambda sentence, word: re.sub(rf'{word}s*', '', sentence, count=1),
filter(lambda x: x[0] if x[1] > 1 else '',
Counter(sentence.split()).items()),
sentence
)
import pdb
pdb.set_trace()
print(result)
# User Key Department Account Start Date

但它并没有打印出预期的内容。奇怪的部分在filter中。如果我只列出筛选的结果:

[el for el in filter(lambda x: x[0] if x[1] > 1 else '', Counter(sentence.split()).items())]
# [('Account', 2)]

不管lambda中指定了什么,x[0]

如果我将一个非false值传递给else子句:

[el for el in filter(lambda x: x[0] if x[1] > 1 else ['foo'], Counter(sentence.split()).items())]
# [('User', 1), ('Key', 1), ('Account', 2), ('Department', 1), ('Start', 1), ('Date', 1)]

我在这里缺少什么?

我想做以下事情:

[el for el in filter(lambda key,value: key if value > 1 else '', Counter(sentence.split()).items())]

得到Account。但它提高了*** TypeError: <lambda>() missing 1 required positional argument: 'value'

使用列表理解可以很好地工作:

[key for key, value in Counter(sentence.split()).items() if value > 1]
# ['Account']

这里的问题是我不确定你在这里想做什么。但我会解释实际发生了什么。

考虑表达式filter(lambda x: x[0] if x[1] > 1 else '', Counter(sentence.split()).items())

filter的第一个自变量是谓词。这是一个接受一个输入(x(并返回一个被解释为布尔值的函数。

在这种情况下,让我们考虑谓词lambda x : x[0] if x[1] > 1 else ''——为了简写,我们将其写成P。我们将假设我们在有序对(a, b)上调用此函数,使得a是字符串,b是数字。

然后我们看到P((a, b)) = a if b > 1 else ''

因此,如果b > 1,则P((a, b))计算为a。该值随后被解释为布尔值(即使它是字符串(,因为P充当谓词。

当我们解读一些";容器";数据类型,如字符串作为布尔值,我们将容器解释为";真像";如果它是非空的;假样";如果它是空的。因此,在这种情况下,当a为非空时,a将被解释为True,而当a为空时,则False

另一方面,当b <= 1时,P((a, b))将计算为'',然后将其解释为False(因为它是空字符串(。

所以P((a, b))是一个字符串,当被解释为布尔值时,它等于b > 1 and (a is non-empty)

因此,当我们调用filter(P, seq)时,其中seq是对(a, b)的序列,a是字符串,b是数字,我们可以看到,我们将保留b > 1a不为空的对(a, b)

事实就是这样。

然而,似乎你想要的是只保留多次出现的项目,而忽略它们的计数。为此,您需要mapfilter的组合。你会想要

map(lambda x: x[0], filter(lambda x: x[1] > 1, Counter(sentence.split()).items()))

这首先只保留对CCD_ 39,其中CCD_。然后它取下每个剩余的对CCD_ 41并且只保留CCD_。

最新更新