2013-05-29 46 views
3

从Python中的大列表中选择项目最有效的方式(就内存和CPU而言)是什么? 这是一个好方法吗?高效的列表剔除

a = range(0,100000) 
a[:] = [item for item in a if item > 10] 

这些数字只是一个例子。也可能是:

a = ["my", "very", "big", "list"] 
a[:] = [item for item in a if item.startswith("b")] 
+2

你的名单不会总是订购吧? – jamylak

+2

Numpy在这里会很好。 – Blender

+2

你是不是指'如果项目> 10' – ajon

回答

2

如果你真的想要一个列表(你要替换的地方原来的列表),你可能不会做一大堆优于什么你有纯Python。但是,这通常不是必需的。通常情况下,您只需要一个可迭代的对象:

generator = (item for item in a if item > 10) 
for item in generator: 
    ... 

这样会提高内存使用效率,性能应该大致相同。

+0

性能增益会是什么?无论如何,这些项目都在记忆中。 – RickyA

+0

@RickyA - 当你做切片分配时,首先评估右侧。如果只过滤了几个项目,则基本上将您的列表存储在内存中两次(在分配回原始列表之前)。这通常不是什么大问题,但是你问过关于内存效率的问题......就性能而言,你需要'timeit',但我希望这两种方法能够在速度上保持一致。 – mgilson

+0

好的,但开销只会是一个引用值的新列表。不是实际值的副本,因为列表理解不会复制值。对? – RickyA

1

Python具有专门为此构建的生成器函数。请参阅文档here。除了使用range(文档建议使用返回发生器的xrange),您的实现非常好。

的文档具有下面的例子:

# Build and return a list 
def firstn(n): 
    num, nums = 0, [] 
    while num < n: 
     nums.append(num) 
     num += 1 
    return nums 

sum_of_first_n = sum(firstn(1000000)) 

这废物的空间很多。因此,文档建议做这样的事情,而不是:

# Using the generator pattern (an iterable) 
class firstn(object): 
    def __init__(self, n): 
     self.n = n 
     self.num, self.nums = 0, [] 

    def __iter__(self): 
     return self 

    def next(self): 
     if self.num < self.n: 
      cur, self.num = self.num, self.num+1 
      return cur 
     else: 
      raise StopIteration() 

sum_of_first_n = sum(firstn(1000000)) 
+0

您能否举个例子 – jamylak

+1

'xrange'不是一个生成器,它是一个序列对象,可以懒惰地评估 – jamylak

+0

看起来你是对的,但我很困惑,因为链接有这样的含义:“范围和xrange都表示一个范围数字,并具有相同的函数签名,但范围返回一个列表,而xrange返回一个生成器(至少在概念上;实现可能不同)。“ – isaach1000

0

您可以使用filtergenerators这里

发电机

>>> data = [10, 20, 4, 4, 11, 13.4] 
>>> custom_filter = (i for i in data if i > 10) 
>>> [j for j in custom_filter] 
[20, 11, 13.4] 
>>> 

过滤

>>> data = [10, 20, 4, 4, 11, 13.4] 
>>> custom_filter = filter(lambda x: x > 10, data) 
>>> custom_filter 
[20, 11, 13.4] 
>>>