【问题标题】:python: recursive expanding list comprehensionpython:递归扩展列表理解
【发布时间】:2018-04-13 14:56:14
【问题描述】:

我一直在环顾四周,但没有完全找到我的具体问题的答案。使我的问题具体的原因是我试图仅使用列表理解。

问题:

使用以下代码:

[print(k,l,m) for k in range(3) for l in range(2) for m in range(1)]

我得到了输出:

0 0 0
0 1 0
1 0 0
1 1 0
2 0 0
2 1 0

这适用于 n=3 或任何硬编码的 n。但是,我想做的是:

[print(k1,k2,...,kn) for k1 in range(n) for k2 in range(n-1) .. for kn in range(1)].

我希望有人能立即看到答案——谢谢!

编辑 解决方案发布在下面,但也为了清楚我希望的格式,这是我使用它打印出编码元组的方式:

n=3
[print(x) for x in itertools.product(*[list(range(i)) for i in range(n,0,-1)])]

(为简单起见,没有在范围上使用反向)。

【问题讨论】:

  • 您的输出与您希望看到的有何不同?请提供所需的输出
  • @bcr 我举了一个 n=3 的例子,但我希望能够对任何非硬编码的 n 做到这一点。
  • ...然后列出压缩不是要走的路。
  • “仅列表推导”是什么意思?您使用了print 和range,它们不是列表推导式。我可以在我的解决方案中使用itertools.product 吗?我可以在列表理解中定义递归 lambda 函数吗?无论如何,在列表理解中做所有事情有什么意义?
  • 如果你从中得到了什么,应该知道这不是列表推导应该做的事情。没有真正的“通过列表理解变得更好”这样的事情。 99% 的列表推导应该是简单的。复杂的列表推导应该是普通的循环或一堆较小的列表推导。

标签: python list recursion list-comprehension


【解决方案1】:

如果允许,您可以使用 itertools.product :

n=3
list(itertools.product(*[list(range(i)) for i in reversed(range(1, n+1))]))

【讨论】:

  • 好吧,这会产生正确的整数组合,但会颠倒过来,并且与问题中的代码顺序不同。
  • 太棒了!绝对朝着正确的方向前进。我也在尝试使用 itertools,添加条件
  • 我修改了代码以使用正确的顺序;)
  • 如果将范围调高一点,我们可以得到正确的顺序: list(itertools.product(*[list(range(i)) for i in range(n,0,-1) ]))
【解决方案2】:

最近有人问了一个非常相似的问题:"[How to] determine all combinations of flipping a coin without using itertools.product?" 我提供了一个答案。我不会认为它是重复的,因为我相信 itertools.product 最适合您的特定问题。

但是,您可能想知道 itertools.product 是如何做到的。或者,也许您想在递归扩展中编码不同的转换。下面,我将分享一个可能的解决方案使用 Python 的生成器

def product (*iters):
  def loop (prod, first = [], *rest):
    if not rest:
      for x in first:
        yield prod + (x,)
    else:
      for x in first:
        yield from loop (prod + (x,), *rest)
  yield from loop ((), *iters)

for prod in product ("ab", "xyz"):
  print (prod)

# ('a', 'x')
# ('a', 'y')
# ('a', 'z')
# ('b', 'x')
# ('b', 'y')
# ('b', 'z')

因为product 接受iterables 的列表,所以产品中可以使用任何可迭代的输入。它们甚至可以像这里展示的那样混合

print (list (product (['@', '%'], range (2), "xy")))
# [ ('@', 0, 'x')
# , ('@', 0, 'y')
# , ('@', 1, 'x')
# , ('@', 1, 'y')
# , ('%', 0, 'x')
# , ('%', 0, 'y')
# , ('%', 1, 'x')
# , ('%', 1, 'y')
# ]

我们可以制作一个程序 foo 来提供您问题中发布的输出

def foo (n):
  def build_ranges (m):
    if m == 0:
      return []
    else:
      return [ range (m) ] + build_ranges (m - 1)
  yield from product (*build_ranges (n))


for prod in foo (3):
  print (prod)

# (0, 0, 0)
# (0, 1, 0)
# (1, 0, 0)
# (1, 1, 0)
# (2, 0, 0)
# (2, 1, 0)

或者使用解构赋值为产品的各个元素创建绑定

for (x,y,z) in foo (3):
  print ("x", x, "y", y, "z", z)

# x 0 y 0 z 0
# x 0 y 1 z 0
# x 1 y 0 z 0
# x 1 y 1 z 0
# x 2 y 0 z 0
# x 2 y 1 z 0

product 实现的其他品质在my answer 中与我链接的问题进行了讨论。如果您有兴趣了解如何在没有生成器的情况下执行此操作,我也提供了一个纯函数式的解决方案。

【讨论】:

    猜你喜欢
    • 2016-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-10
    • 2020-10-17
    相关资源
    最近更新 更多