简体   繁体   English

Python中的递归列表理解?

[英]Recursive list comprehension in Python?

Is it possible to define a recursive list comprehension in Python?是否可以在 Python 中定义递归列表理解?

Possibly a simplistic example, but something along the lines of:可能是一个简单的例子,但大致如下:

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

Is anything like this possible?这样的事情有可能吗?

No, there's no (documented, solid, stable, ...;-) way to refer to "the current comprehension".不,没有(有记录的、可靠的、稳定的,...;-) 方式来指代“当前的理解”。 You could just use a loop:你可以只使用一个循环:

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

of course this is very costly (O(N squared)), so you can optimize it with an auxiliary set (I'm assuming that keeping the order of items in res congruent to that of the items in nums , otherwise set(nums) would do you;-)...:当然,这是非常昂贵的(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)

this is enormously faster for very long lists (O(N) instead of N squared).对于很长的列表(O(N) 而不是 N 平方),这要快得多。

Edit : in Python 2.5 or 2.6, vars()['_[1]'] might actually work in the role you want for self (for a non-nested listcomp)... which is why I qualified my statement by clarifying there's no documented, solid, stable way to access "the list being built up" -- that peculiar, undocumented "name" '_[1]' (deliberately chosen not to be a valid identifier;-) is the apex of "implementation artifacts" and any code relying on it deserves to be put out of its misery;-).编辑:在Python 2.5或2.6, vars()['_[1]']实际上可能你想为角色工作self (对于非嵌套listcomp)...这就是为什么我澄清有资格我的发言没有记录的、可靠的、稳定的方式来访问“正在建立的列表”——那个奇特的、未记录的“名称” '_[1]' (故意选择不是一个有效的标识符;-)是“实现工件的顶点” "并且任何依赖于它的代码都应该摆脱它的痛苦;-)。

Actually you can!其实你可以! This example with an explanation hopefully will illustrate how.这个带有解释的例子有望说明如何。

define recursive example to get a number only when it is 5 or more and if it isn't, increment it and call the 'check' function again.定义递归示例以仅在 5 或更多时获取数字,如果不是,则增加它并再次调用“检查”函数。 Repeat this process until it reaches 5 at which point return 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] ]

result:结果:

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

essentially the two anonymous functions interact in this way:本质上,这两个匿名函数以这种方式交互:

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
             }

make g,f the 'same' function except that in one or both add a clause where the parameter is modified so as to cause the terminal condition to be reached and then go f(g,x) in this way g becomes a copy of f making it like:使 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
             }

You need to do this because you can't access the the anonymous function itself upon being executed.您需要这样做,因为您无法在执行时访问匿名函数本身。

ie IE

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

so in this example let A = the first function and B the second.所以在这个例子中,让 A = 第一个函数,B = 第二个。 We call A passing B as f and i as v. Now as B is essentially a copy of A and it's a parameter that has been passed you can now call B which is like calling A.我们称 A 传递 B 为 f,i 为 v。现在 B 本质上是 A 的副本,并且它是已传递的参数,您现在可以调用 B,就像调用 A 一样。

This generates the factorials in a list这将生成列表中的阶乘

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

Starting Python 3.8 , and the introduction of assignment expressions (PEP 572) ( := operator), which gives the possibility to name the result of an expression, we could reference items already seen by updating a variable within the list comprehension: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]

This:这个:

  • Initializes a list acc which symbolizes the running list of elements already seen初始化一个列表acc ,它象征着已经看到的元素的运行列表
  • For each item, this checks if it's already part of the acc list;对于每个项目,这会检查它是否已经是acc列表的一部分; and if not:如果不:
    • appends the item to acc ( acc := acc + [x] ) via an assignment expression通过赋值表达式将项目附加到acc ( acc := acc + [x] )
    • and at the same time uses the new value of acc as the mapped value for this item同时使用acc的新值作为该项的映射值

Not sure if this is what you want, but you can write nested list comprehensions:不确定这是否是您想要的,但您可以编写嵌套列表推导式:

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

From your code example, you seem to want to simply eliminate duplicates, which you can do with sets:从您的代码示例中,您似乎只想简单地消除重复项,您可以使用集合来做到这一点:

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

no.不。 it won't work, there is no self to refer to while list comprehension is being executed.它不起作用,在执行列表理解时没有self可以参考。

And the main reason of course is that list comprehensions where not designed for this use.主要原因当然是列表推导式不是为此用途而设计的。

No.不。

But it looks like you are trying to make a list of the unique elements in nums.但看起来您正在尝试列出 nums 中的唯一元素。

You could use a set :你可以使用一set

unique_items = set(nums)

Note that items in nums need to be hashable.请注意, nums 中的项目需要是可散列的。

You can also do the following.您还可以执行以下操作。 Which is a close as I can get to your original idea.这是一个接近,因为我可以得到你的原始想法。 But this is not as efficient as creating a set .但这不如创建set

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

Do this:做这个:

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

or even this:甚至这个:

unique_num_list = sorted(set_of_nums)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM