Python中的布尔值列表到整数

Posted

技术标签:

【中文标题】Python中的布尔值列表到整数【英文标题】:Boolean values list to integer in Python 【发布时间】:2020-08-29 15:16:30 【问题描述】:

我在使用这种 lambdas 语法时遇到了问题。 我正在尝试将布尔值列表转换为整数值,但出现错误,我不明白为什么。

代码如下:

from functools import reduce

binary = [True, True, False, True]

L = list(range(len(binary)))      #Step 1
print(L)                          #[0, 1, 2, 3]
L = map(lambda a: 2**a, L)        #Step 2
print(L)                          #[1, 2, 4, 8]
L = zip(binary, L)                #Step 3
print(L)                          #[(True, 1),(True, 2),(False, 4),(True, 8)]
L = filter(lambda a, b: a, L)     #Step 4
print(L)                          #[(True, 1),(True, 2),(True, 8)] not sure
L = map(lambda a, b: b, L)        #Step 5
print(L)                          #?????
L = reduce(lambda a, b: a + b, L) #Final step 
print(L)                          #11

输出:

Traceback (most recent call last):
  File "C:/Users/axel_/PycharmProjects/Python_Subject_Exam/19_new_exam_binary_list_translation.py", line 27, in <module>
    L = reduce(lambda a, b: a + b, L)
TypeError: <lambda>() missing 1 required positional argument: 'b'
[0, 1, 2, 3]
<map object at 0x00000267FAFE5388>
<zip object at 0x00000267FAFE50C8>
<filter object at 0x00000267FAFE5248>
<map object at 0x00000267FAFE4EC8>

Process finished with exit code 1

谁能帮我调试一下?

【问题讨论】:

mapreduce 在 python3 中返回一个生成器。所以,你只需要在打印时将L 转换为list ......就像这样:print( list(L) ) 知道了@Anwarvic 感谢您的回复,但我仍然在想为什么我不能执行reduce 如果您遵循@Anwarvic 的建议,您将能够在调用 reduce 之前看到输出。这可能会帮助您确定您的问题。 您的错误在这里L = filter(lambda a, b: a, L) 过滤器采用带有 single 参数的 lambda。更好的选择是将其表示为 L = (b for a, b in L if a) 这是filter 的生成器表达式版本。 使用生成器表达式实际上可以将整个操作简化为sum(2**i for i, b in enumerate(binary) if b) 【参考方案1】:

我认为这将解决您的问题。我会在代码中写一些cmets来帮助大家理解:

from functools import reduce

binary = [True, True, False, True]
L = list(range(len(binary)))       #[0, 1, 2, 3]

L = map(lambda a: 2**a, L)         #[1, 2, 4, 8]

L = zip(binary, L)                 #[(True, 1), (True, 2), (False, 4), (True, 8)]

L = filter(lambda x: x[0], L)      #<--- an item from zip() is an ((unpacked)) tuple

L = map(lambda x: x[1], L)
L = reduce(lambda a, b: a + b, L)
print(L)                           #11

【讨论】:

“将你的地图对象投射到列表 zip() 期望可迭代而不是生成器”这是一个不好的建议,生成器是可迭代的(列表也是如此)。 是的,你是对的。这是不必要的。我已经编辑了我的代码【参考方案2】:

如果您是使用迭代器的新手,这是挑战之一。

迭代器在每个项目被拉出迭代器时被评估,这意味着当你调用reduce来组合结果时,所有的lambda表达式都会被评估。您的示例 this 等效于以下表达式:

L = list(range(len(binary)))
L = reduce(lambda a, b: a + b, 
    map(lambda a, b: b, 
        filter(lambda a, b: a, 
            zip(binary, 
                map(lambda a: 2**a, L)
            )
        )
    )
)
print(L)  

困惑?

在您的示例中,L = filter(lambda a, b: a, L) #Step 4 行有错误。过滤器表达式接受一个可调用表达式,该表达式接受一个 single 参数和一个可迭代的参数,但是因为它没有被计算到最后,你会得到一个令人困惑的错误。

一种方法(在调试时也是一种很好的方法)是将每个步骤包装在对 list 的调用中,以强制在每一行上进行评估,例如L = list(filter(lambda a, b: a, L))。这将使错误的位置更加明显。

或者使用生成器表达式而不是filter/map 例如:

# filter (return odd numbers between 1 and 10)
result_a = filter(lambda a: a % 2, range(1, 11))
result b = (a for a in range(1, 11) if a % 2)

# map (return powers of 2)
result_a = map(lambda a: 2**a, range(11))
result_b = (2**a for a in range(11))

所有的结果都是一样的,但是生成器表达式有另一个技巧,你可以使用元组解包,它允许:

result = (b for a, b in zip(binary, range(len(binary))) if a)

此外,python 还有其他内置函数可以进一步简化代码。

Enumerate 将返回一个计数器加上可迭代的每个元素,从而将前 3 个步骤简化为:

# 1 step 1, 2 and 3 can be simplified with enumerate
L = ((i**2, b) for i, b in enumerate(L))

下一个 sum 可以用来代替 reduce,sum 将所有数值相加在一个 iterable 中:

L = reduce(lambda a, b: a + b, L)
# is equivalent to
L = sum(L)

将它们放在一起整个序列可以简化为:

L = sum(2**i for i, b in enumerate(binary) if b)

希望对您有所帮助。

【讨论】:

以上是关于Python中的布尔值列表到整数的主要内容,如果未能解决你的问题,请参考以下文章

位向量与布尔值列表的性能

Python:如何检查列表是不是包含数值并返回布尔值?

python - 用两个不同列表中的值替换列表的布尔值[重复]

python中的整数浮点数和布尔值

Python Bool 和 int 比较以及使用布尔值对列表进行索引

Python Bool和int比较以及带有布尔值的列表索引