2010-04-14 106 views
30

是否有可能在Python中定義遞歸列表理解?Python中的遞歸列表理解?

可能是一個簡單的例子,但沿線的東西:

nums = [1, 1, 2, 2, 3, 3, 4, 4] 
willThisWork = [x for x in nums if x not in self] # self being the current comprehension 

是這樣可能什麼?

+4

如果訂單不是問題,則使用list(set(num))'。否則,請查看http://docs.python.org/library/itertools.html中的'unique_everseen'。 – kennytm 2010-04-14 15:05:48

+0

泄漏抽象警報。理解不應該被認爲是循環,在我看來,即使它們可能在cpython中被實現爲循環.. – wim 2013-04-16 03:49:46

回答

30

不,沒有(記錄的,穩定的,穩定的...... ;-)方式來指代「目前的理解」。你可以只使用一個循環:

res = [] 
for x in nums: 
    if x not in res: 
    res.append(x) 
當然

這是非常昂貴的(O(N的平方)),這樣你就可以有輔助set(我假設優化它,保持項目的順序在res全等在nums的項目,否則set(nums)會做你; - )...:

res = [] 
aux = set() 
for x in nums: 
    if x not in aux: 
    res.append(x) 
    aux.add(x) 

這是巨大的很長的列表(O(N)更快的替代N的平方)。

編輯:在Python 2.5或2.6,vars()['_[1]']實際上可能在你想要的角色self工作(對於非嵌套listcomp)...這就是爲什麼我澄清沒有合格證明我的說法,穩定,穩定訪問「正在建立的列表」的方法 - 特殊的,未公開的「名稱」'_[1]'(故意選擇不成爲有效的標識符;-)是「實現工件」的頂點和任何依賴它的代碼應該擺脫它的苦難;-)。

+1

設置的操作使它成爲O(n log(n)),我很確定。 – 2010-04-14 16:30:26

+2

@ Python中的dash-tom-bang集合並不像紅黑樹那樣實現(就像在STL中一樣),但是據我所知,它使用散列,所以它將是O(N)。 – 2010-04-14 18:38:13

+1

@Justin是正確的 - python集合和字典是非常優化的散列,其中O(1)分攤成本用於添加項目,O(1)成本用於查找。 – 2010-04-15 00:38:18

2

沒有。它將不起作用,在列表理解正在執行時沒有self的引用。

而主要原因當然是列表解析不是爲這個用途而設計的。

1

不知道這是否是你想要的,但你可以寫嵌套列表理解:

xs = [[i for i in range(1,10) if i % j == 0] for j in range(2,5)] 
assert xs == [[2, 4, 6, 8], [3, 6, 9], [4, 8]] 

從你的代碼示例,你似乎要簡單地消除重複,你可以帶套做:

xs = sorted(set([1, 1, 2, 2, 3, 3, 4, 4])) 
assert xs == [1, 2, 3, 4] 
1

編號

但它看起來像你正在努力使nums中的獨特元素的列表。

你可以使用一個set

unique_items = set(nums) 

注意,在NUMS項目需要哈希的。

您還可以執行以下操作。這是一個接近,因爲我可以達到你的原始想法。但是這並不像創建set那樣有效。

unique_items = [] 
for i in nums: 
    if i not in unique_items: 
     unique_items.append(i) 
2

這樣做:

nums = [1, 1, 2, 2, 3, 3, 4, 4] 
set_of_nums = set(nums) 
unique_num_list = list(set_of_nums) 

,甚至這樣的:

unique_num_list = sorted(set_of_nums) 
+0

列表解析是不必要的。 'unique_num_list = list(set_of_nums)'。 'sorted(set_of_nums)'返回一個列表。 – 2010-04-15 09:19:28

+0

@PreludeAndFugue:好點。我會改變代碼。 – hughdbrown 2010-04-15 21:51:01

8

其實你可以!這個例子有一個解釋,希望能說明如何。

定義遞歸的例子,只有當它是5或更多時纔得到一個數字,如果不是,遞增它並再次調用'check'函數。重複這個過程,直到它在這一點回報5.

print [ (lambda f,v: v >= 5 and v or f(f,v+1))(lambda g,i: i >= 5 and i or g(g,i+1),i) for i in [1,2,3,4,5,6] ] 

結果達到5:

[5, 5, 5, 5, 5, 6] 
>>> 

基本上是兩個匿名函數以這種方式互動:

let f(g,x) = { 
       expression, terminal condition 
       g(g,x), non-terminal condition 
      } 

let g(f,x) = { 
       expression, terminal condition 
       f(f,x), non-terminal condition 
      } 

賺G,F '相同'的功能,除了在一個或兩個添加一個子句,其中的參數被修改,以便達到終端條件,然後以這種方式去g(x,x)g這是一個f的副本,使其如下所示:

f(g,x) = { 
       expression, terminal condition 
       { 
        expression, terminal condition, 
        g(g,x), non-terminal codition 
       }, non-terminal condition 
      } 

您需要這樣做,因爲您在執行時無法訪問匿名函數本身。

(lambda f,v: somehow call the function again inside itself)(_,_) 

所以在這個例子中,讓A =所述第一功能和B的第二個。我們稱A通過B爲f,i爲v現在,因爲B本質上是A的一個副本,並且它已經通過了一個參數,現在可以調用B,就像調用A一樣。

這會生成一個階乘清單

print [ (lambda f,v: v == 0 and 1 or v*f(f,v-1))(lambda g,i: i == 0 and 1 or i*g(g,i-1),i) for i in [1,2,3,5,6,7] ] 

[1, 2, 6, 120, 720, 5040] 
>>> 
+2

克隆lambda是不必要的;你可以使用通用代理作爲第一個lambda來允許任何第二個lambda自己調用。 '(lambda f,arg:f(f,arg))(lambda self,v:....,firstvalue)' – 2014-11-03 19:20:40