簡體   English   中英

Python中的遞歸列表理解?

[英]Recursive list comprehension in 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

這樣的事情有可能嗎?

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

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

當然,這是非常昂貴的(O(N squared)),因此您可以使用輔助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]' (故意選擇不是一個有效的標識符;-)是“實現工件的頂點” "並且任何依賴於它的代碼都應該擺脫它的痛苦;-)。

其實你可以! 這個帶有解釋的例子有望說明如何。

定義遞歸示例以僅在 5 或更多時獲取數字,如果不是,則增加它並再次調用“檢查”函數。 重復這個過程直到達到 5,此時返回 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, 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 成為 f(g,x) 的副本f 使它像:

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

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

IE

(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]
>>> 

Python 3.8開始,並引入了賦值表達式 (PEP 572):=運算符),它提供了命名表達式結果的可能性,我們可以通過更新列表推導式中的變量來引用已經看到的項目:

# items = [1, 1, 2, 2, 3, 3, 4, 4]
acc = []; [acc := acc + [x] for x in items if x not in acc]
# acc = [1, 2, 3, 4]

這個:

  • 初始化一個列表acc ,它象征着已經看到的元素的運行列表
  • 對於每個項目,這會檢查它是否已經是acc列表的一部分; 如果不:
    • 通過賦值表達式將項目附加到acc ( acc := acc + [x] )
    • 同時使用acc的新值作為該項的映射值

不確定這是否是您想要的,但您可以編寫嵌套列表推導式:

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]

不。 它不起作用,在執行列表理解時沒有self可以參考。

主要原因當然是列表推導式不是為此用途而設計的。

不。

但看起來您正在嘗試列出 nums 中的唯一元素。

你可以使用一set

unique_items = set(nums)

請注意, nums 中的項目需要是可散列的。

您還可以執行以下操作。 這是一個接近,因為我可以得到你的原始想法。 但這不如創建set

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

做這個:

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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM