Python的列表理解语法,可以很容易地理解一个过滤器内的值。 例如:
result = [x**2 for x in mylist if type(x) is int]
将返回MYLIST整数的平方的列表。 然而,如果测试涉及到一些(昂贵)的计算,并要对结果进行过滤? 一种选择是:
result = [expensive(x) for x in mylist if expensive(x)]
这将导致非“假”昂贵(x)的值的列表,但是昂贵的()为每个x叫了两声。 是否有一个理解语法,允许你做这个测试,而只有调用每一次X贵吗?
如果计算已经很好地捆绑到功能,如何使用filter
和map
?
result = filter (None, map (expensive, mylist))
您可以使用itertools.imap
如果该列表是非常大的。
想出了思想的一分钟后,我自己的答案。 它可以与嵌套的内涵进行:
result = [y for y in (expensive(x) for x in mylist) if y]
我想这作品,虽然我觉得嵌套的内涵是只能勉强可读
最明显的(并且我认为最可读的)答案是不使用列表理解或发电机的表达,而是一个真正的发电机:
def gen_expensive(mylist):
for item in mylist:
result = expensive(item)
if result:
yield result
它需要更多的横向空间,但它更容易看到它做什么,一目了然,你最终不会重复自己。
result = [x for x in map(expensive,mylist) if x]
地图()将返回在MYLIST每个对象的值的列表传递给昂贵()。 然后,你可以列出,理解这一点,放弃不必要的值。
这有点像一个嵌套的理解,但应该快了(因为Python解释器可以很方便地优化它)。
这是发电机适合于处理到底是什么:
result = (expensive(x) for x in mylist)
result = (do_something(x) for x in result if some_condition(x))
...
result = [x for x in result if x] # finally, a list
- 这使得它完全清楚是什么在管道的每个阶段发生。
- 明确了隐
- 使用发电机随处可见,直到最后一步,所以没有大的中间列表
CF: “发电机诀窍系统程序员”由大卫·比兹利
你总是可以memoize的的expensive()
函数,以便调用它的第二次,仅仅是为了计算值查找x
。
这里只是memoize的的许多实现的装饰之一 。
你可以memoize的昂贵(X)(如果你经常打电话贵(X),你应该memoize的任何方式本页面给出了蟒蛇memoize的的实现:
http://code.activestate.com/recipes/52201/
这有昂贵(x)可以比N次被少跑,因为任何重复的条目将利用备忘录上一次执行额外的好处。
请注意,这是假定贵(x)是一个真正的功能,并且不依赖于可能改变外部状态。 如果贵(X)不依赖于外部的状态,您可以在检测到状态的改变,或者你知道它不会列表理解过程中改变,那么你就可以修真前的备忘录复位。
我将有一个偏好:
itertools.ifilter(bool, (expensive(x) for x in mylist))
这样做的优点是:
- 避免无作为功能(将在Python 3被消除): http://bugs.python.org/issue2186
- 只使用迭代器。
还有就是普通的老使用的for
循环追加到一个列表,太:
result = []
for x in mylist:
expense = expensive(x)
if expense:
result.append(expense)
文章来源: How do I efficiently filter computed values within a Python list comprehension?