将列表值转换为布尔值

2024-09-29 02:24:14 发布

您现在位置:Python中文网/ 问答频道 /正文

我想转化的是这样的东西

a = [ 0, 10, 3, 2, 0, 2 ]

def covert_to_boolean(a)
     ...
    return a_converted

a_coverted = [ 0, 1, 1, 1, 0, 1]

像这样转换的最简单方法是什么?你知道吗


Tags: to方法returndefconvertedbooleancovertcoverted
3条回答

要转换为真正的布尔值,可以使用:

def covert_to_boolean(a)
    return [bool(x) for x in a]

这是回报

[False, True, True, True, False, True]

如果您更喜欢0和1,那么:

    return [int(bool(x)) for x in a]

将返回:

[0, 1, 1, 1, 0, 1]

除非代码是程序中最热门的代码,否则实际上不建议这样做,但有一些方法可以改进:

def covert_to_boolean(a)
    return [bool(x) for x in a]
    # Or the straightforward way of converting back to 1/0
    return [int(bool(x)) for x in a]

首先,如果a足够大,因为int/bool是用C实现的内置程序,您可以使用map删除字节码解释器开销:

def covert_to_boolean(a)
    return [*map(bool, a)]
    # Or converting back to 1/0
    return [*map(int, map(bool, a))]

另一个节省可以来自不使用bool构造函数(C构造函数调用在CPython上有不可避免的开销,即使结果实际上没有“构造”任何东西),并且用operator.truth(一个只接受一个参数的普通函数,CPython对其进行了大量优化)替换它可以显著减少开销,而且使用它可以将开销减少40%:

>>> import random
>>> from operator import truth
>>> a = random.choices([*[0] * 100, *range(1, 101)], k=1000)
>>> %%timeit -r5
... [bool(x) for x in a]
...
...
248 µs ± 7.82 µs per loop (mean ± std. dev. of 5 runs, 1000 loops each)
>>> %%timeit -r5
... [*map(bool, a)]
...
...
140 µs ± 2.5 µs per loop (mean ± std. dev. of 5 runs, 10000 loops each)

>>> %%timeit -r5
... [*map(truth, a)]
...
...
81.3 µs ± 3.91 µs per loop (mean ± std. dev. of 5 runs, 10000 loops each)

map(bool提高了大约45%的单子理解力,反过来又被map(truth击败了40%(map(truth几乎占据了单子理解力的三分之一)。你知道吗

如果结果必须是int,我们可以将其扩展为[*map(int, map(truth, a))],但是int是一个构造函数,即使它返回单实例值(CPython缓存-5到256的单个副本作为实现细节),它仍然会支付构造函数开销(更糟的是,因为它可以接受关键字参数)。没有像bool那样的等效“convert to trueint”函数有operator.truth,但是您可以通过“adding to 0”将您的方式欺骗为一个:

>>> %%timeit -r5
... [int(bool(x)) for x in a]
...
...
585 µs ± 65.2 µs per loop (mean ± std. dev. of 5 runs, 1000 loops each)

>>> %%timeit -r5
... [*map(int, map(bool, a))]
...
...
363 µs ± 58.6 µs per loop (mean ± std. dev. of 5 runs, 1000 loops each)

>>> %%timeit -r5
... [*map((0).__add__, map(truth, a))]
...
...
168 µs ± 2.2 µs per loop (mean ± std. dev. of 5 runs, 10000 loops each)

(0).__add__只是利用了这样一个事实:将bool添加到0会产生01__add__的开销远远低于构造函数;在这种情况下,从列表理解切换到map(甚至嵌套的map)节省了近40%,从int/bool切换到(0).__add__/truth节省了几乎55%的剩余时间,运行时间减少了70%以上。你知道吗

再说一次,要清楚,不要这样做,除非:

  1. 您已经分析了,转换实际上是您的代码中的关键路径,在速度方面,以及
  2. 输入不是太小(如果a只是五个元素,那么调用map的设置开销将超过避免每个循环使用字节码所节省的微小开销)

但当它出现的时候,很高兴知道。bool是Python中速度最慢的东西之一间接费用:生产性工作类似于int的事物的int比率也同样糟糕。你知道吗

不过,还有最后一件事要检查。也许把事情推进语法,避免函数调用,可以节省更多。碰巧,答案是“是的,对他们中的一个来说”:

>>> %%timeit -r5
... [not not x for x in a]  # Worse than map
...
...
122 µs ± 6.6 µs per loop (mean ± std. dev. of 5 runs, 10000 loops each)

>>> %%timeit -r5
... [0 + (not not x) for x in a]  # BETTER than map!!!
...
...
158 µs ± 22.4 µs per loop (mean ± std. dev. of 5 runs, 10000 loops each)

>>> %%timeit -r5
...: [0 + x for x in map(truth, a)]  # Somehow not the best of both worlds...
...:
...:
177 µs ± 5.77 µs per loop (mean ± std. dev. of 5 runs, 10000 loops each)

虽然[not not x for x in a]输给了[*map(truth, a)][0 + (not not x) for x in a]实际上打败了[*map((0).__add__, map(truth, a))](碰巧,通过tp_add槽周围的包装器调用(0).__add__会有一些开销,这可以通过在Python层实际使用+来避免)。不过,将每种解决方案中的最佳方案(map(truth与list comp中的0 +)混合使用实际上并没有给我们带来好处(读取字节码开销大致是一个固定成本,not not甚至比operator.truth还要快)。关键是,除非您真的需要,否则这些都不值得,而且性能可能是不直观的。我曾经有过需要它的代码,所以你可以从我的测试中受益。你知道吗

您可以在列表理解中使用and运算符来保持代码的快速性和可读性:

def covert_to_boolean(a)
    return [i and 1 for i in a]

此方法比@ShadowRanger的最快方法更快,如下所示: https://repl.it/@blhsing/NeglectedClientsideLanserver

相关问题 更多 >