繁体   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