1

http://docs.python.org/2/library/itertools.html#itertools.productによると、次の関数はライブラリを使用することと同等です (必要のないものをいくつか削除しました)。

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)

私の場合、製品関数 3 リストを渡していますが、いくつかの条件チェックを追加する必要があるため、要件を満たさない場合に、あるリストの特定のアイテムと別のリストのアイテムが混在しないようにします。だから私がする必要があると思ったのは、変換することです:

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

「通常の」FOR ループ (それらを参照する方法がわからない) に変換するため、いくつかの IF チェックを追加して、リスト内の項目を混在させる必要があるかどうかを確認できます。

主に私を混乱させるのは、「x」が空の「結果」リストを反復しているということですが、反復すると項目が追加されるため、これが通常のループへの変換を複雑にしていると思います。

これが私の試みの1つです:

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)

どんな助けでも大歓迎です!

4

3 に答える 3

4

あなたは非常に近いです: ネストされたリスト内包表記の右側は、for ループを書くのと同じ順序で書かれているので、その通りです。ただし、listcomp バージョンでは、最初に割り当ての RHS が計算され、次に LHS の名前にバインドされます。そう

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

なる必要がある

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

resultそれを繰り返しながら変更しないようにします。特定の配置を禁止したい場合(左から右への反復順序で機能するように制約を記述できる場合)、次のようにできます。

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)

を与える

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

これが単純に使用するよりもメリットがあるかどうかは、(p for p in itertools.product(whatever) if condition(p))削除できるブランチの数に依存します。これは、ご覧のとおり、すべての中間リストがメモリ内に構築されるためです。

于 2013-01-30T21:49:53.490 に答える
3

product 関数は一般的にリダクション操作の形式でリストを掛け合わせています。これは、結果をフィルタリングしようとしている場合にはおそらく役に立たないでしょう。代わりに、固定数のリストを取る積関数を作成する必要があります。

for x in list1:
    for y in list2:
        for z in list3:
            if condition(x, y, z):
                yield tuple(x, y, z)
于 2013-01-30T21:53:32.740 に答える
2

result = [x+[y] for x in result for y in pool]行に ,が 2 回表示されますが、関係ないことに注意してくださいresult。この式は、古い を使用してリストを作成し、resultこの新しいリストを に割り当てresultます。

それがあなたを混乱させたのでしょう。同等の拡張バージョンは次のようになります。

def product(*args):
    pools = map(tuple, args)
    result = [[]]
    for pool in pools:
        tmp = []
        for x in result:   # note that it's the old 'result' here
            for y in pool:
                tmp.append(x+[y])
        result = tmp
    for prod in result:
        yield tuple(prod)
于 2013-01-30T21:49:49.463 に答える