web-dev-qa-db-ja.com

リストのすべての可能な組み合わせを作成する

入力されたリストのすべての可能な組み合わせを含むリストを作成できる必要があります。たとえば、リスト[1,2,3][1 [1,2] [1,3] 2 [2,3] 3 [1,2,3]]を返す必要がありますリストは特定の順序である必要はありません。このサイトでは、itertoolsを使用する多くの関数を見つけましたが、listだけが必要なときにオブジェクトを返しています。

43
Deano

itertools.combinations 。例えば:

import itertools

lst = [1, 2, 3]
combs = []

for i in xrange(1, len(lst)+1):
    combs.append(i)
    els = [list(x) for x in itertools.combinations(lst, i)]
    combs.append(els)

これでcombsがこの値を保持します:

[1, [[1], [2], [3]], 2, [[1, 2], [1, 3], [2, 3]], 3, [[1, 2, 3]]]

はい、それはあなたが提供したサンプル出力とは少し異なりますが、その出力ではすべての可能な組み合わせをリストしていませんでした。

組み合わせのサイズをリストしていますbefore各サイズの実際のリスト、必要なのは単に組み合わせである場合(サンプル出力に表示されるサイズなし)次に、これらの他のバージョンのコードを試してください:

import itertools

lst = [1, 2, 3]
combs = []

for i in xrange(1, len(lst)+1):
    els = [list(x) for x in itertools.combinations(lst, i)]
    combs.extend(els)

これでcombsがこの値を保持します:

[[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
52
Óscar López

itertoolsモジュールは、リストの代わりにgeneratorsを返しますが、

  • 多くの場合、ジェネレーターはリストよりも効率的です(特に、多数の組み合わせを生成する場合)
  • 本当に必要なときは、list(...)を使用してジェネレータをリストにいつでも変換できます。

chaincombinationsおよびitertools関数は正常に機能します、ただし、使用する必要があるPython 2.6以降:

import itertools

def all_combinations(any_list):
    return itertools.chain.from_iterable(
        itertools.combinations(any_list, i + 1)
        for i in xrange(len(any_list)))

その後、これを次のように呼び出すことができます。

# as a generator
all_combinations([1,2,3])  # --> <itertools.chain at 0x10ef7ce10>

# as a list
list(all_combinations([1,2,3]))  # --> [(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]

# as a list of lists
[list(l) for l in all_combinations([1,2,3])]  # --> [[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]

以前にジェネレーターを使用したことがない場合は、次のようにジェネレーターをリストであるかのようにループすることに注意してください。

# a generator returned instead of list
my_combinations = all_combinations([1,2,3])

# this would also work if `my_combinations` were a list
for c in my_combinations:
    print "Combo", c

"""
Prints:
  Combo (1,)
  Combo (2,)
  Combo (3,)
  Combo (1, 2)
  Combo (1, 3)
  Combo (2, 3)
  Combo (1, 2, 3)
"""

パフォーマンスの違いは劇的です。パフォーマンスを比較すると、ジェネレーターの作成がはるかに高速であることがわかります。

# as a generator
all_combinations(range(25))  # timing: 100000 loops, best of 3: 2.53 µs per loop

# as a list
list(all_combinations(range(25)))  # timing: 1 loops, best of 3: 9.37 s per loop

いずれの場合でも、すべての組み合わせを繰り返すにはまだ時間がかかりますが、特に探しているものを早期に見つけた場合は、大きな勝利になる可能性があることに注意してください。

11
Arel

Itertoolsモジュールの関数は反復子を返します。これらをリストに変換するために必要なことは、結果に対してlist()を呼び出すことだけです。

ただし、itertools.combinationsを3回(異なる長さごとに1回)呼び出す必要があるため、list.extendを使用して、イテレータのすべての要素を最終リストに追加できます。

以下を試してください:

import itertools
in_list = [1, 2, 3]
out_list = []
for i in range(1, len(in_list)+1):
    out_list.extend(itertools.combinations(in_list, i))

または、リストの理解として:

out_list = [c for i in range(len(in_list)) for c in itertools.combinations(in_list, i+1)]

これらは次のリストになります。

[(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]

タプルの代わりにリストが必要な場合、および単一の長さのタプルを値だけに変換するには、以下を実行できます。

out_list = [x[0] if len(x) == 1 else list(x) for x in out_list]
# [1, 2, 3, [1, 2], [1, 3], [2, 3], [1, 2, 3]]

または、単一のアイテムをリストとして残すには:

out_list = map(list, out_list)
6
Andrew Clark

ループ内でitertools.combinationsを使用して問題を解決できます。

>>> l = [1,2,3]
>>> comb = []
>>> for i in range(len(l)):
...   comb += itertools.combinations(l,i+1)
... 
>>> comb
[(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]

そしてそれらをリストとして欲しい場合:

>>> comb_list = [ list(t) for t in comb ]
>>> comb_list
[[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]

EDIT:組み合わせの最初のパラメーターは反復可能で、2番目のパラメーターは結果のタプルの長さです(この場合、1からlen(l))。

組み合わせの詳細: http://docs.python.org/library/itertools.html#itertools.combinations

6
juliomalegria
l = [1,2,3]
combs = reduce(lambda x, y: list(itertools.combinations(l, y)) + x, range(len(l)+1), [])

1つのライナーが必要な場合。

ここで他の答えを簡単なPython 3の例に要約する価値があると思います:

from itertools import chain, combinations

def all_combinations(array):
    return chain(*(list(combinations(array, i + 1)) for i in range(len(array))))

これは、値を表示するために反復可能を返します:

>>> print(list(all_combinations((1, 2, 3))))
[(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
0
Ninjakannon