2009-11-23 43 views
-1

Python的用戶列表理解構建是最有用的?Python - 最有用的列表理解構建

我已經創建了以下兩個量詞,我用做不同的驗證操作:

def every(f, L): return not (False in [f(x) for x in L]) 
def some(f, L): return True in [f(x) for x in L] 

優化的版本(requres的Python 2.5+)的建議如下:

def every(f, L): return all(f(x) for x in L) 
def some(f, L): return any(f(x) for x in L) 

所以,怎麼運行的?

"""For all x in [1,4,9] there exists such y from [1,2,3] that x = y**2""" 
answer = every([1,4,9], lambda x: some([1,2,3], lambda y: y**2 == x)) 

使用這樣的操作,你可以很容易做到智能驗證,如:

"""There exists at least one bot in a room which has a life below 30%""" 
answer = some(bots_in_this_room, lambda x: x.life < 0.3) 

等等,你可以回答,即使使用這樣的量詞非常複雜的問題。當然,Python中沒有無限的列表(嘿,它不是Haskell :)),但是Python的列表解析非常實用。

你有自己喜歡的名單,理解建築?

PS:我想知道,爲什麼大多數人往往不會回答問題但批評的例子?問題是關於最愛列表 - 理解建構。

+5

社區維基,如果有的話 – 2009-11-23 15:47:09

+3

這些功能都是自2.5開始構建的。 http://docs.python.org/library/functions.html – 2009-11-23 15:47:57

+1

@Fred:更高效。 – 2009-11-23 15:49:13

回答

2

爲了您的信息,python 3.x中的模塊itertools的文檔列出了一些相當不錯的生成器函數。

13
any

all是從2.5標準Python的一部分。沒有必要製作你自己的版本。如果可能,anyall的正式版本也會短路評估,從而提高性能。你的版本總是迭代整個列表。

如果你想接受謂詞版本,使用這樣的事情,充分利用現有的anyall功能:

def anyWithPredicate(predicate, l): return any(predicate(x) for x in l) 
def allWithPredicate(predicate, l): return all(predicate(x) for x in l) 

我並不特別看需要對這些功能雖然,因爲它不真的不會節省很多打字。

此外,隱藏現有標準的Python功能與​​自己的函數具有相同的名稱,但不同的行爲是不好的做法。

+0

完全錯誤。可能我選擇了令人困惑的名字。在Python中,所有的和完全不同的東西!如果bool(x)對於迭代中的所有值x都爲True,那麼Python的buildin全部返回True。我的功能需要2個參數 - 一個函數和一個列表。 – psihodelia 2009-11-23 15:54:36

+0

謂詞是封閉的.net術語。這是我第一次記得在python中看到它。真的anyWithPredicate是一個非標準的Python命名約定一般 – 2009-11-23 16:00:14

+0

從http://docs.python.org/library/itertools.html「itertools.dropwhile(predicate,iterable)」 – 2009-11-23 16:04:34

4

該解決方案內建陰影一般爲主意。然而,使用感覺相當pythonic,它保留了原有的功能。

注有幾種方法可以潛在地優化此基礎上的測試,包括移動進口伸到模塊級和改變F公司默認爲無並測試它,而不是使用默認的λ和我一樣。

def any(l, f=lambda x: x): 
    from __builtin__ import any as _any 
    return _any(f(x) for x in l) 

def all(l, f=lambda x: x): 
    from __builtin__ import all as _all 
    return _all(f(x) for x in l) 

只是把它放在那裏考慮,看看人們怎麼看待這麼做可能會變得很髒。

+0

這就是我一直希望內建工作的方式。 – 2009-11-23 16:31:59

5

有不是所有的許多情況下,列表解析(LC的簡稱)將基本上比等效發生器表達更爲有用(GE爲短,即,使用圓括號代替方括號,一次生成一個項目,而不是「在開始時全部批量生成」)。

有時,您可以通過「投資」額外的內存來一次保存列表,這取決於一種或另一種Python版本的優化和垃圾回收的變幻莫測,但可以獲得一點額外的速度, LC對GE的有用性。

實質上,與GE相比,爲了從LC中獲得大量的額外用量,您需要在序列上本質上需要「多次通過」的用例。在這種情況下,通用電氣會要求您每次都要生成一次序列,而使用LC可以生成序列一次,然後在其上執行多次通過(僅支付一次發電成本)。如果GE/LC基於不平凡的可重新啓動的基礎迭代器(例如,實際上是Unix管道的「文件」),那麼多次生成也可能會產生問題。

例如,假設您正在讀取一個非空白的打開文本文件f,它有一串由空格分隔的數字(文本表示)(包括換行符,空行等)。你可以將其轉化爲數字與無論是GE的順序:

G = (float(s) for line in f for s in line.split()) 

或LC:

L = [float(s) for line in f for s in line.split()] 

哪一個更好?取決於你在做什麼(即用例!)。如果你想要的只是總和,總和(G)和總和(L)也可以。如果你想得到平均值,那麼和(L)/ len(L)對於列表來說是好的,但對於發生器不起作用 - 考慮到「重新啓動f」的困難,爲了避免中間列表,你必須這樣做:

tot = 0.0 
for i, x in enumerate(G): tot += x 
return tot/(i+1) 

無處爲活潑,快速,簡潔大方爲return sum(L)/len(L)

記住sorted(G)並返回一個列表(不可避免的),所以L.sort()(這是就地)是大致相當於在這種情況下 - 排序(L)將份外(因爲現在你有2名名單) 。因此,當需要分類時,簡單地說,簡單起見,發電機通常是優選的。總而言之,由於L與list(G)完全相同,所以很難對通過標點符號(方括號而不是圓括號)表達它的能力感到非常興奮,而不是像單個的,簡短的,可讀的和明顯的詞一樣list ;-)。這就是所有的LC - 基於標點符號的語法快捷方式list(some_genexp) ...!