【问题标题】:Alter elements of a list更改列表的元素
【发布时间】:2009-01-03 20:07:28
【问题描述】:

我有一个布尔值列表,有时我会将它们全部重置为 false。首先将重置写为:

for b in bool_list:
    b = False

我发现它不起作用。我花了一点时间挠头,然后想起这当然行不通,因为我只是更改了对 bool 的引用,而不是它的值。于是我改写为:

for i in xrange(len(bool_list)):
    bool_list[i] = False

一切正常。但我发现自己在问,“这真的是改变列表中所有元素的最 Pythonic 的方式吗?”还有其他方法可以更有效或更清晰吗?

【问题讨论】:

  • 这不是非常Pythonic。一个布尔值列表有什么珍贵之处,以至于你无法重建它?您能否提供更多关于此的背景信息?
  • 在这种情况下没有什么禁止重构列表的。

标签: python coding-style


【解决方案1】:

如果您只有一个对列表的引用,以下可能会更容易:

bool_list = [False] * len(bool_list)

这将创建一个填充有False 元素的新列表。

请参阅我对Python dictionary clear 的回答以获取类似示例。

【讨论】:

  • 投了反对票,因为他表示他需要它才能在现有列表中起作用。
  • 投了赞成票,因为“现有列表”可以通过赋值语句轻松替换为新列表。
  • 另外,如果要更改现有列表,可以将其更改为 bool_list[:] = [False] * len(bool_list)
  • 如果这是一个非常大的列表,这段代码可能很糟糕,因为您实际上是在制作列表的两个副本。但它应该适用于大约 95% 的所有情况。
【解决方案2】:

这是另一个版本:

bool_list = [False for item in bool_list]

【讨论】:

    【解决方案3】:

    总结 在性能方面,numpy 或列表乘法是明显的赢家,因为它们比其他方法快 10-20 倍。

    我对提出的各种选项进行了一些性能测试。我在 Linux (Ubuntu 8.10) 上使用 Python 2.5.2 和 1.5 Ghz Pentium M。

    原文:

    python timeit.py -s 'bool_list = [True] * 1000' 'for x in xrange(len(bool_list)): bool_list[x] = False'
    

    1000 次循环,3 次中的最佳:每个循环 280 微秒

    使用列表理解的基于切片的替换:

    python timeit.py -s 'bool_list = [True] * 1000' 'bool_list[:] = [False for element in bool_list]'
    

    1000 个循环,3 次中最好的:每个循环 215 微秒

    使用生成器理解的基于切片的替换:

    python timeit.py -s 'bool_list = [True] * 1000' 'bool_list[:] = (False for element in bool_list)'
    

    1000 次循环,3 次中的最佳:每个循环 265 微秒

    枚举

    python timeit.py -s 'bool_list = [True] * 1000' 'for i, v in enumerate(bool_list): bool_list[i] = False'
    

    1000 次循环,3 次中的最佳:每个循环 385 微秒

    Numpy

    python timeit.py -s 'import numpy' -s 'bool_list = numpy.zeros((1000,), dtype=numpy.bool)' 'bool_list[:] = False'
    

    10000 次循环,3 次中的最佳:每个循环 15.9 微秒

    使用列表乘法的基于切片的替换:

    python timeit.py -s 'bool_list = [True] * 1000' 'bool_list[:] = [False] * len(bool_list)'
    

    10000 次循环,3 次中的最佳:每个循环 23.3 微秒

    使用列表乘法替换引用

     python timeit.py -s 'bool_list = [True] * 1000' 'bool_list = [False] * len(bool_list)'
    

    10000 次循环,3 次中的最佳:每个循环 11.3 微秒

    【讨论】:

    • 我很高兴我为他们计时。到目前为止,我一直认为列表乘法很简洁,但可能很慢。
    • 这是一个很好的总结!您应该将此标记为答案。我不知道 numpy 快得多。当
    【解决方案4】:
    bool_list[:] = [False] * len(bool_list)
    

    bool_list[:] = [False for item in bool_list]
    

    【讨论】:

    • 因为这种风格的效果很明显,不受列表只有一个参考的限制,并且排名靠前的表现出色。
    【解决方案5】:

    如果您愿意使用 numpy 数组,那么使用数组切片实际上很容易做到这一点。

    import numpy
    
    bool_list = numpy.zeros((100,), dtype=numpy.bool)
    
    # do something interesting with bool_list as if it were a normal list
    
    bool_list[:] = False
    # all elements have been reset to False now
    

    【讨论】:

      【解决方案6】:

      我不会使用范围和 len。使用 enumerate() 会干净很多

      for i, v in enumerate(bool_list): #i, v = index and value
          bool_list[i] = False
      

      在这种情况下,它留下了一个未使用的变量,但在我看来它仍然看起来更干净。性能也没有明显变化。

      【讨论】:

      • 在这种情况下,枚举似乎是矫枉过正。您甚至不需要 v 变量,这是过度复杂的明确指标。一个简单的列表推导即可完成工作。
      • 为了更好看,我还是投给它。速度没有明显差异。一个虚拟变量是值得的。我想这取决于个人口味
      • 在它需要的所有单独的 setitem 中效率低下。
      【解决方案7】:

      对于 int、bool 和 string 等值类型,您的第二个示例几乎与它所获得的一样漂亮。您的第一个示例适用于任何引用类型,例如类、字典或其他列表。

      【讨论】:

      • 第一个示例只有在您不尝试更改列表中包含的项目时才会“工作”。如果你在 a: x.foo() 中为 x 做,那当然没问题。但是,如果 a 是一个 dicts 列表,那么 for x in a: x = {} 不会执行预期的操作,原因与原始问题相同。
      【解决方案8】:

      我觉得

      bool_list = [False for element in bool_list]
      

      就像 Python 一样。使用这样的列表通常应该比 python 中的 for 循环更快。

      【讨论】:

      • 为什么要重复上一个答案?为什么不赞成另一个答案?我不确定这个答案有什么不同。也许我错过了一些东西。您能否修改或扩展您的答案以强调独特的信息?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-01-03
      • 1970-01-01
      • 2023-03-07
      • 2021-11-16
      • 2019-05-10
      • 1970-01-01
      • 2023-03-03
      相关资源
      最近更新 更多