【问题标题】:Recursive list comprehension in Python?Python中的递归列表理解?
【发布时间】:2010-04-14 15:03:27
【问题描述】:

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

这样的事情可能吗?

【问题讨论】:

  • 如果订单不是问题,list(set(num))。否则,在docs.python.org/library/itertools.html 中检查unique_everseen
  • 泄漏抽象警报。在我看来,理解不应该被认为是循环,即使它们可以在 cpython 中实现为循环..

标签: python list-comprehension


【解决方案1】:

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

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 的角色中工作(对于非嵌套列表计算)......这就是我限定我的原因通过澄清没有记录的、可靠的、稳定的方式来访问“正在建立的列表”——那个特殊的、未记录的“名称”'_[1]'(故意选择不是有效的标识符;- ) 是“实现工件”的顶点,任何依赖它的代码都应该摆脱它的痛苦;-)。

【讨论】:

  • 设置操作使它成为 O(n log(n)),我很确定。
  • @dash-tom-bang Python 中的集合没有实现为红黑树(如在 STL 中),但据我所知,它使用散列代替,所以它将是 O(N)。
  • @Justin 是正确的——python 集和字典是经过优化的哈希,添加项目的摊销成本为 O(1),查找成本为 O(1)。
【解决方案2】:

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

定义递归示例以仅在数字为 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 成为'same'函数,只是在其中一个或两个中添加一个修改参数的子句,以便达到终止条件然后执行 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 = 第二个。我们将传递 B 的 A 称为 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]
>>> 

【讨论】:

  • 克隆 lambda 是不必要的;您可以使用通用代理作为第一个 lambda,以允许任何类型的第二个 lambda 调用自身。 (lambda f,arg: f(f,arg))(lambda self,v: .... , firstvalue)
【解决方案3】:

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 列表中;如果不:
    • 通过赋值表达式将项目附加到acc (acc := acc + [x])
    • 同时使用acc的新值作为此项的映射值

【讨论】:

  • 真不错,以后一定会用
【解决方案4】:

不确定这是否是您想要的,但您可以编写嵌套列表推导:

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]

【讨论】:

    【解决方案5】:

    没有。它不起作用,在执行列表理解时没有 self 可供参考。

    当然,主要原因是列表推导不是为此用途而设计的。

    【讨论】:

      【解决方案6】:

      没有。

      但您似乎正在尝试列出 nums 中的唯一元素。

      你可以使用set:

      unique_items = set(nums)
      

      请注意,nums 中的项目需要是可散列的。

      您还可以执行以下操作。我可以接近您的原始想法。但这不如创建set 高效。

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

      【讨论】:

        【解决方案7】:

        这样做:

        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)
        

        【讨论】:

        • 列表推导是不必要的。 unique_num_list = list(set_of_nums)sorted(set_of_nums) 返回一个列表。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-03-10
        • 2020-10-17
        • 1970-01-01
        • 2012-07-26
        • 2021-01-07
        • 1970-01-01
        • 2016-02-06
        相关资源
        最近更新 更多