如何将Python的itertools.product库从列表理解转换为正常的for循环? [英] How do I convert Python's itertools.product library from a list comprehension to normal for loops?

查看:159
本文介绍了如何将Python的itertools.product库从列表理解转换为正常的for循环?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据 http://docs.python.org/2/ library / itertools.html#itertools.product 下面的函数相当于使用它们的库(我从中删除了一些我不需要的东西):

  def product(* args):
#product('ABCD','xy') - > AxeAxBx通过CxCyDxDy
池= map(tuple,args)
result = [[]]
池中的池:
result = [x + [y]在结果中用于x的结果在池中]
for prod结果:
产生元组(prod)

在我的情况下,我正在传递产品函数3列表,但是我需要添加一些条件检查,所以它不会混合来自一个列表的某些项目与另一个列表中的项目,如果它们不符合要求。所以我想我需要做的是转换:

  result = [x + [y] for x in result for y in pool ] 

转换为正常FOR循环(不知道如何引用它们),所以我可以添加几个IF检查,以验证列表中的项目是否应该混合在一起。



主要困惑我的是x遍历结果列表这是空的,但项目被添加到它,因为它迭代,所以我认为这是什么复杂的转换为正常循环对我来说。

这是我的尝试:

  def product(* args):
pools = map(tuple,args)
result = [[]]
池中的池:
为结果中的x:
为池中的y:
result.append(x + [y])
prod in:
yield tuple(prod)

非常感谢任何帮助! p>

解决方案

你非常接近:嵌套列表理解的右边是按照你写for循环的顺序编写的,所以你说得对。但是,在listcomp版本中,首先计算任务的RHS,然后绑定到LHS的名称。所以

  result = [x + [y] for x in result for y in pool] 

$ b $ p $ < ]
for result in:
for pool in $:
new_result.append(x + [y])
result = new_result

因此,您在迭代时不会修改 result 。如果你想禁止某些安排,那么你可以编写你的约束条件,使它适用于从左到右填充的迭代顺序。那么你可以这样做:

$ $ $ $ $ $ $ $ c $ def $过滤产品$ args filter_fn
pool = map(tuple,args)
result = [[]]
池中的池:
new_result = []
为结果中的x:
为池中的y:
new_val = x + [y]
if filter_fn(new_val):
new_result.append(x + [y])
result = new_result
print'intermediate result:',result
for prod in result :
产生元组(prod)

给出
$在[25]:list(filtered_product([[1,2,3],[4,5,6],[7,8,9]]中,b $ b

  lambda x:sum(x)%3!= 2))
中间结果:[[1],[3]]
中间结果:[[1,5],[1,6], [3,4],[3,6]]
中间值结果:[[1,5,7],[1,5,9],[1,6,8],[1,6,9],[3,4,8],[3,4,9] ,[3,6,7],[3,6,9]]
Out [25]:
[(1,5,7),
(1,5,9) ,
(1,6,8),
(1,6,9),
(3,4,8),
(3,4,9),
b $ b(3,6,7),
(3,6,9)]

是否这给你任何好处,而不是简单地使用(p for itertools.product(无论)如果条件(p))将取决于你有多少分支可以修剪,因为你可以看到它构造了内存中的所有中间列表。


According to http://docs.python.org/2/library/itertools.html#itertools.product the following function is equivalent to using their library (I removed a few things I don't need from it):

def product(*args):
    # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
    pools = map(tuple, args)
    result = [[]]
    for pool in pools:
        result = [x+[y] for x in result for y in pool]
    for prod in result:
        yield tuple(prod)

In my case I'm passing the product function 3 lists, but I need to add some conditional checks, so it doesn't mix certain items from one list with items in another list if they don't meet the requirements. So what I figured I need to do is convert:

result = [x+[y] for x in result for y in pool]

into "normal" FOR loops (not sure how to refer to them), so I can add several IF checks to verify whether the items in the lists should be mixed together or not.

What mainly confuses me is that "x" is iterating through the "result" list which is empty, but items are added to it as it iterates, so I think this is what is complicating the conversion to normal loops for me.

Here is one of my attempts:

def product(*args):
    pools = map(tuple, args)
    result = [[]]
    for pool in pools:
        for x in result:
            for y in pool:
                result.append(x+[y])
    for prod in result:
        yield tuple(prod)

Any help is greatly appreciated!

解决方案

You're very close: the right hand side of a nested list comprehension is written in the same order that you'd write the for loops, so you've got that right. However, in the listcomp version, first the RHS of the assignment is computed and then it's bound to the name on the LHS. So

result = [x+[y] for x in result for y in pool]

needs to become

new_result = []
for x in result:
    for y in pool:
        new_result.append(x+[y])
result = new_result

So that you're not modifying result as you iterate over it. If you wanted to forbid certain arrangements -- and you can write your constraint in such a way that it works for that iteration order, which fills in from left-to-right -- then you could do this:

def filtered_product(args, filter_fn):
    pools = map(tuple, args)
    result = [[]]
    for pool in pools:
        new_result = []
        for x in result:
            for y in pool:
                new_val = x+[y]
                if filter_fn(new_val):
                    new_result.append(x+[y])
        result = new_result
        print 'intermediate result:', result
    for prod in result:
        yield tuple(prod)

which gives

In [25]: list(filtered_product([[1,2,3], [4,5,6], [7,8,9]], lambda x: sum(x) % 3 != 2))
intermediate result: [[1], [3]]
intermediate result: [[1, 5], [1, 6], [3, 4], [3, 6]]
intermediate result: [[1, 5, 7], [1, 5, 9], [1, 6, 8], [1, 6, 9], [3, 4, 8], [3, 4, 9], [3, 6, 7], [3, 6, 9]]
Out[25]: 
[(1, 5, 7),
 (1, 5, 9),
 (1, 6, 8),
 (1, 6, 9),
 (3, 4, 8),
 (3, 4, 9),
 (3, 6, 7),
 (3, 6, 9)]

Whether or not this gives you any benefit over simply using (p for p in itertools.product(whatever) if condition(p)) will depend upon how many branches you can prune, because as you can see it constructs all the intermediate lists in memory.

这篇关于如何将Python的itertools.product库从列表理解转换为正常的for循环?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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