1

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

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

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

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

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

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

4

3 回答 3

2

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

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

对于您的场景:

#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.dropwhile()和来自 itertools 文档nth()配方。

于 2012-10-05T18:51:30.493 回答
1

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

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

构建它看起来像这样:

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

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

于 2012-10-05T19:01:51.020 回答
1

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

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

于 2012-10-05T19:17:10.000 回答