Python中的递归列表理解?

时间:2010-04-14 15:03:28

标签: python list-comprehension

是否可以在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

这样的事情可能吗?

7 个答案:

答案 0 :(得分:33)

不,没有(记录的,稳定的,稳定的,...... ;-)方式来引用“当前的理解”。你可以使用一个循环:

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) 会对你有用; - )......:

vars()['_[1]']
对于很长的列表(O(N)而不是N平方),这个速度要快得多。

编辑:在Python 2.5或2.6中,self实际上可能适用于'_[1]'所需的角色(对于非嵌套的listcomp)...这是为什么我通过澄清没有记录的,稳固的,稳定的方式来访问“正在建立的列表”来证明我的陈述 - 那个奇特的,无证件的“名称”{{1}}(故意选择不是一个有效的标识符;-)是“实现工件”的顶点,任何依赖它的代码都应该摆脱它的痛苦; - )。

答案 1 :(得分:11)

其实你可以!这个带有解释的例子有望说明如何。

定义递归示例以仅在数字为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成为'相同'的函数,除了在一个或两个中添加一个子句,其中参数被修改,以便达到终端条件,然后去 以这种方式f(g,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 :(得分:1)

没有。它不起作用,在执行列表理解时没有self来引用。

当然,主要原因是列表理解不适用于此用途。

答案 3 :(得分: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]

答案 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)

答案 5 :(得分:1)

这样做:

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)

答案 6 :(得分:0)

Python 3.8开始,并引入assignment expressions (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列表中;如果不:
    • 通过分配表达式
    • 将该项附加到accacc := acc + [x]
    • 并同时使用新值acc作为此项的映射值