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
谁能帮我调试一下?
【问题讨论】:
map
和 reduce
在 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 - 用两个不同列表中的值替换列表的布尔值[重复]