布尔值列表为 Python 中的整数

Boolean values list to integer in Python

我在使用 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

谁能帮我调试一下?

我想这会解决你的问题。我会在代码里写一些注释帮助大家理解:

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

如果您不熟悉使用迭代器,这是挑战之一。

迭代器在从迭代器中拉出每个项目时进行计算,这意味着当您调用 reduce 组合结果时,所有 lambda 表达式都会在此时进行计算。在您的示例中,这等效于以下表达式:

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 有错误。过滤器表达式接受一个可调用表达式,该表达式接受一个 单个 参数和一个可迭代对象,但是因为它没有被评估到最后你会收到一个令人困惑的错误。

一种方法(在调试时是一种很好的方法)是将每个步骤包装在对 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 将 return 一个计数器加上一个 iterable 中的每个元素,允许将前 3 个步骤简化为:

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

下一个sum可以用来代替reducesum把所有的数值加到一个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)

希望对您有所帮助。