【问题标题】:Efficient use of Python list comprehensions高效使用 Python 列表推导
【发布时间】:2012-10-06 03:17:10
【问题描述】:

我有一个可能很长的 Python 对象列表。在特定时间,我对列表中具有特定属性的所有元素感兴趣,例如flag,其评估结果为 False。为此,我一直在使用列表推导,如下所示:

objList = list()
# ... populate list
[x for x in objList if not x.flag]

这似乎运作良好。形成子列表后,我可能需要执行一些不同的操作:

  1. 下标子列表以获取索引 ind 处的元素。
  2. 计算子列表的长度(即具有flag == False 的元素的数量)。
  3. 在子列表中搜索特定对象的第一个实例(即使用列表的 .index() 方法)。

我已经使用简单的方法实现了这些,即形成子列表,然后使用它的方法获取我想要的数据。我想知道是否有更有效的方法来解决这些问题。 #1和#3至少看起来可以优化,因为在#1中我只需要子列表的第一个ind + 1匹配元素,不一定是整个结果集,而在#3中我只需要搜索子列表,直到我找到匹配的元素。

有没有很好的 Pythonic 方法来做到这一点?我猜我可能能够以某种方式使用() 语法来获取生成器而不是创建整个列表,但我还没有找到正确的方法。我显然可以手动编写循环,但我正在寻找像基于理解的方法一样优雅的东西。

【问题讨论】:

    标签: python list-comprehension


    【解决方案1】:

    如果您需要多次执行这些操作中的任何一个,其他方法的开销会更高,列表是最好的方法。它也可能是最清晰的,所以如果内存不是问题,那么我建议直接使用它。

    如果内存/速度是个问题,那么还有其他替代方案 - 请注意,在速度方面,这些方案实际上可能会更慢,具体取决于您的软件的常见情况。

    对于您的场景:

    #value = sublist[n]
    value = nth(x for x in objList if not x.flag, n)
    
    #value = len(sublist)
    value = sum(not x.flag for x in objList)
    
    #value = sublist.index(target)
    value = next(dropwhile(lambda x: x != target, (x for x in objList if not x.flag)))
    

    使用 itertools 文档中的 itertools.dropwhile()the nth() recipe

    【讨论】:

    • 为什么是consume() 而不是nth()
    • @KennyTM 很棒的建议,应该阅读一下 - 编辑为使用 nth(),这是一个更好的解决方案 - 没有必要重新发明轮子。
    【解决方案2】:

    我假设你可能会做这三件事中的任何一件,而且你可能会做不止一次。

    在这种情况下,您想要的基本上是编写一个惰性求值的列表类。它将保留两条数据,一个 real list 评估项目的缓存,以及其余数据的生成器。然后你可以做ll[10],它会评估到第10个项目ll.index('spam'),它会评估直到找到'spam',然后是len(ll),它会评估列表的其余部分,同时缓存在真实的列表中它所看到的,所以什么都不做。

    构造它看起来像这样:

    LazyList(x for x in obj_list if not x.flag)
    

    但在您像上面那样真正开始使用它之前,实际上不会计算任何内容。

    【讨论】:

    • 使用这种方法,如果基础列表发生更改,我将需要某种方式通知LazyList 实例。我在 OP 中没有明确说明这一点,但 objList 可以在我搜索它的时间之间改变。
    • 在这种情况下,您只需创建一个新的LazyList
    【解决方案3】:

    由于您评论说您的objList 可以更改,如果您不需要索引或搜索 objList 本身,那么您最好只存储两个不同的列表,一个带有 @ 987654322@ 和一个.flag = False。然后您可以直接使用第二个列表,而不是每次都使用列表推导来构造它。

    如果这适用于您的情况,这可能是最有效的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多