如何在Python中“扁平化"生成器? [英] How to 'flatten' generators in python?

查看:89
本文介绍了如何在Python中“扁平化"生成器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在python中拉平"某些生成器时遇到问题.这是我的代码:

I have a problem with 'flattening' out some generators in python. Here is my code:

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

但是,我想要类似的东西

However, I want something like:

[(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],其中nlen(test).在这里,它在每个步骤中拾取一个元素.

In general the function should give me generators for all possible paths to go through a list, i.e. from test[0] -> test[1] -> ... -> test[n] where n is len(test). Here, it picks up at each step one element.

类似于以下函数返回的内容,仅与生成器有关:

Similar to what the following function returns, just with generators:

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.chainit.chain.from_iterable,但似乎无法使其正常工作.问题是我的测试"列表的大小和长度是可变的,因此我必须递归地进行整个操作.

I played around with it.chain and it.chain.from_iterable but can't seem to make it work. The problem is that my 'test' list are variable in size and length and thus I have to do the whole thing recursively.

itertools.product(*test)

正如约翰·科尔曼(John Coleman)指出的那样工作

works as pointed out by John Coleman

推荐答案

这是不使用内置函数即可计算列表product的一种方法

Here's one way to calculate a product of lists without using the built-in

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构造函数将生成器的输出收集在一个列表中.请注意,我们还可以计算两个以上输入的乘积,如下所示

In python, we can collect the outputs of a generator in a list by using the list constructor. Note we can also calculate the product of more than two inputs as seen below

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接受 iterables 的列表,因此该产品中可以使用任何可迭代的输入.它们甚至可以混合在一起,如下所示

Because product accepts a a list of iterables, any iterable input can be used in the product. They can even be mixed as demonstrated below

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)所示

Because product is defined as a generator, we are afforded much flexibility even when writing more complex programs. Consider this program that finds right triangles made up whole numbers, a Pythagorean triple. Also note that product allows you to repeat an iterable as input as see in product (r, r, r) below

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)

有关其他说明以及查看如何不使用生成器的方法,请查看此答案.

For additional explanation and a way to see how to do this without using generators, view this answer.

这篇关于如何在Python中“扁平化"生成器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆