python - 如何在 python 中“扁平化”生成器?
问题描述
我在 python 中“扁平化”一些生成器时遇到问题。这是我的代码:
import itertools as it
test = [[1,2,3],[4,5],[6,7,8]]
def comb(possible):
if len(possible) != 1:
for a in possible[0]:
yield from it.product((a,), comb(possible[1:]))
else:
yield from possible[0]
list(comb(test))
这给了我:
[(1, (4, 6)),
(1, (4, 7)),
(1, (4, 8)),
(1, (5, 6)),
(1, (5, 7)),
(1, (5, 8)),
(2, (4, 6)),
(2, (4, 7)),
(2, (4, 8)),
(2, (5, 6)),
(2, (5, 7)),
(2, (5, 8)),
(3, (4, 6)),
(3, (4, 7)),
(3, (4, 8)),
(3, (5, 6)),
(3, (5, 7)),
(3, (5, 8))]
但是,我想要类似的东西:
[(1, 4, 6),
(1, 4, 7),
(1, 4, 8),
(1, 5, 6),
(1, 5, 7),
(1, 5, 8),
(2, 4, 6),
(2, 4, 7),
(2, 4, 8),
(2, 5, 6),
(2, 5, 7),
(2, 5, 8),
(3, 4, 6),
(3, 4, 7),
(3, 4, 8),
(3, 5, 6),
(3, 5, 7),
(3, 5, 8)]
一般来说,该函数应该为我提供所有可能路径的生成器以通过列表,即from test[0] -> test[1] -> ... -> test[n]
where n
is len(test)
。在这里,它在每一步都选择一个元素。
类似于以下函数返回的内容,只是使用生成器:
def prod(possible):
if len(possible) != 1:
b = []
for i in range(len(possible[0])):
for x in prod(possible[1:]):
if len(possible) == 2:
b += [[possible[0][i]]+[x]]
else:
b += [[possible[0][i]]+x]
return b
else:
return possible[0]
prod(test)
我玩过it.chain
,it.chain.from_iterable
但似乎无法让它工作。问题是我的“测试”列表的大小和长度是可变的,因此我必须递归地完成整个事情。
编辑:
itertools.product(*test)
正如约翰科尔曼指出的那样工作
解决方案
这是一种product
不使用内置计算列表的方法
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')
在 python 中,我们可以使用构造函数将生成器的输出收集到一个列表中list
。请注意,我们还可以计算两个以上输入的乘积,如下所示
print (list (product ("+-", "ab", "xyz")))
# [ ('+', 'a', 'x')
# , ('+', 'a', 'y')
# , ('+', 'a', 'z')
# , ('+', 'b', 'x')
# , ('+', 'b', 'y')
# , ('+', 'b', 'z')
# , ('-', 'a', 'x')
# , ('-', 'a', 'y')
# , ('-', 'a', 'z')
# , ('-', 'b', 'x')
# , ('-', 'b', 'y')
# , ('-', 'b', 'z')
# ]
因为product
接受一个可迭代的列表,所以任何可迭代的输入都可以在产品中使用。它们甚至可以混合如下所示
print (list (product (['@', '%'], range (2), "xy")))
# [ ('@', 0, 'x')
# , ('@', 0, 'y')
# , ('@', 1, 'x')
# , ('@', 1, 'y')
# , ('%', 0, 'x')
# , ('%', 0, 'y')
# , ('%', 1, 'x')
# , ('%', 1, 'y')
# ]
因为product
被定义为生成器,所以即使在编写更复杂的程序时,我们也能获得很大的灵活性。考虑这个找到由整数组成的直角三角形的程序,即毕达哥拉斯三元组。另请注意,它product
允许您重复一个可迭代作为输入,product (r, r, r)
如下所示
def is_triple (prod):
(a,b,c) = prod
return a * a + b * b == c * c
def solver (n):
r = range (1,n)
for p in product (r, r, r):
if is_triple (p):
yield p
print (list (solution in solver (20)))
# (3, 4, 5)
# (4, 3, 5)
# (5, 12, 13)
# (6, 8, 10)
# (8, 6, 10)
# (8, 15, 17)
# (9, 12, 15)
# (12, 5, 13)
# (12, 9, 15)
# (15, 8, 17)
有关其他说明和查看如何在不使用生成器的情况下执行此操作的方法,请查看此答案。
推荐阅读
- asp.net-core - Azure Pipeline - 增加内部版本号并在 Web 应用程序中显示
- python - 数据未绘制,但没有错误
- java - 如何在 Spring Boot 中使用抽象类?
- r - 使用循环循环通过 R 中的 API 调用
- java - 使用 Math.random 随机生成 100 个唯一数字
- jquery - 通过 jquery 在 Boostrap 4 轮播中添加“活动”类,从 mongodb 加载数据时无法正常工作
- vagrant - 如果配置 Vagrant 文件到 forward_port 不起作用怎么办;有什么选择吗?
- .net - Azure 应用设置中的 Key Vault 设置,没有代码
- postgresql - 如何在不多次加入自身的情况下进行数据透视表
- javascript - 如何禁用 $('#bootstrap-table') 中的选定字段