web-dev-qa-db-ja.com

Python

[1,2,3]の配列があります

配列のすべての要素を使用して、可能なすべての組み合わせを作成したいと思います。

結果:

[[1], [2], [3]]
[[1,2], [3]]
[[1], [2,3]]
[[1,3], [2]]
[[1,2,3]]
36
user2880257

このニースの質問が復活したので、ここに新しい答えがあります。

問題は再帰的に解決されます。すでにn-1要素のパーティションがある場合、それを使用してn要素をパーティション化するにはどうすればよいですか? n番目の要素を既存のサブセットの1つに配置するか、それを新しいシングルトンサブセットとして追加します。それで十分です。 itertoolsなし、セットなし、繰り返し出力なし、合計npartition()の呼び出しのみ:

def partition(collection):
    if len(collection) == 1:
        yield [ collection ]
        return

    first = collection[0]
    for smaller in partition(collection[1:]):
        # insert `first` in each of the subpartition's subsets
        for n, subset in enumerate(smaller):
            yield smaller[:n] + [[ first ] + subset]  + smaller[n+1:]
        # put `first` in its own subset 
        yield [ [ first ] ] + smaller


something = list(range(1,5))

for n, p in enumerate(partition(something), 1):
    print(n, sorted(p))

出力:

1 [[1, 2, 3, 4]]
2 [[1], [2, 3, 4]]
3 [[1, 2], [3, 4]]
4 [[1, 3, 4], [2]]
5 [[1], [2], [3, 4]]
6 [[1, 2, 3], [4]]
7 [[1, 4], [2, 3]]
8 [[1], [2, 3], [4]]
9 [[1, 3], [2, 4]]
10 [[1, 2, 4], [3]]
11 [[1], [2, 4], [3]]
12 [[1, 2], [3], [4]]
13 [[1, 3], [2], [4]]
14 [[1, 4], [2], [3]]
15 [[1], [2], [3], [4]]
47
alexis

提案された私のコメントとは異なり、私はitertoolsベースの比較的高速なソリューションをすばやく見つけることができませんでした!編集:これはもはや真実ではありません、私はitertoolsを大幅に使用してかなり短い(しかし遅くて読めない)ソリューションを持っています。これは私が代わりに得たものです:

アイデアは、リストの長さに加算される整数のすべての組み合わせを見つけ、その長さのスライスを持つリストを取得することです。

例えば。長さ3のリストの場合、組み合わせまたはパーティションは、(3)、(2、1)、(1、2)および(1、1、1)です。したがって、リストの最初の3つのアイテムを返します。最初の2つ、次に次の1。最初の1、次の2、最初の1、次の1、次の1。

here から整数分割のコードを取得しました。ただし、パーティション関数はパーティションのすべての順列を返すわけではありません(つまり、3の場合、(3)、(2、1)および(1、1、1)を返すだけです。したがって、_itertools.permutations_を呼び出す必要があります次に、重複を削除する必要があります-permutations([1, 2, 3])が_[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]_であるのと同様に、permutations([1, 1, 1])は_[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]]_です。重複を削除する簡単な方法は、タプルの各リストをsetに変換します。

次に残っているのは、タプル内の長さのリストのスライスを取得することです。例えば。 f([1, 2, 3], [0, 0, 1, 2, 1, 0])は_[[0], [0, 1], [2, 1, 0]]_に移動します。

それの私の定義はこれです:

_def slice_by_lengths(lengths, the_list):
    for length in lengths:
        new = []
        for i in range(length):
            new.append(the_list.pop(0))
        yield new
_

今、私たちはすべてを組み合わせます:

_def subgrups(my_list):
    partitions = partition(len(my_list))
    permed = []
    for each_partition in partitions:
        permed.append(set(itertools.permutations(each_partition, len(each_partition))))

    for each_Tuple in itertools.chain(*permed):
        yield list(slice_by_lengths(each_Tuple, deepcopy(my_list)))

>>> for i in subgrups(my_list):
        print(i)

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

また、プログラムの上部で_import itertools_および_from copy import deepcopy_も実行する必要があります。

編集:あなたの与えられた出力は不明確です。私はあなたが私に与えた関数が欲しかったと思いますが、あなたの出力には_[[1,3],[2]]_も含まれています。ここで、出力の要素は別の順序になっています。提案された残りの出力とは異なります(私は自由に推測しました)実際には_[[1, 2], [3]]_ではなく_[[1, 2], 3]_が必要です)。

つまり、あなたが出力として与えるつもりだったのはこれだと思います:

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

実際にそれがこれだった場合:

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

次に、元のリストの3長の順列ごとにsubgrupsを呼び出すだけです。 itertools.permutations(my_list, len(my_list))の順列ごとに。

編集:短いitertoolsベースのソリューションの私の約束を守るために。警告-判読不能で遅い可能性があります。

まず、_slice_by_lengths_を次のように置き換えます。

_def sbl(lengths, the_list):
    for index, length in enumerate(lengths):
        total_so_far = sum(lengths[:index])
        yield the_list[total_so_far:total_so_far+length]
_

次に、 this の回答から、整数パーティション関数を取得します。

_def partition(number):
    return {(x,) + y for x in range(1, number) for y in partition(number-x)} | {(number,)}
_

この関数は実際には整数パーティションのすべての順列を取得するため、必要ありません。

_for each_partition in partitions:
    permed.append(set(itertools.permutations(each_partition, len(each_partition))))
_

もう。ただし、これは再帰的であるため(かつ、Pythonで実装しているため)、以前のものよりもかなり低速です。

次に、それを組み立てます。

_def subgrups(my_list):
    for each_Tuple in partition(len(my_list)):
        yield list(slice_by_lengths(each_Tuple, deepcopy(my_list)))
_

または読みにくくなりますが、関数定義はありません:

_def subgrups(my_list):
    for each_Tuple in (lambda p, f=lambda n, g:
                          {(x,) + y for x in range(1, n) for y in g(n-x, g)} | {(n,)}:
                              f(p, f))(len(my_list)):
        yield list(my_list[sum(each_Tuple[:index]):sum(each_Tuple[:index])+length] for index, length in enumerate(each_Tuple))
_

これは関数定義と2行なので、最初に述べたものとかなり似ています(ただし、可読性ははるかに低く、速度はかなり遅くなります)。

(この関数はsubgrupsと呼ばれます。質問は元々「すべてのサブグループ」を見つけることを求めていたためです)

10
rlms

more_itertools.set_partitions を検討してください。

与えられた

import more_itertools as mit


lst = [1, 2, 3]

コード

kセットパーティションの範囲をフラット化します。

[part for k in range(1, len(lst) + 1) for part in mit.set_partitions(lst, k)]

出力

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

more_itertools はサードパーティのパッケージです。 > pip install more_itertoolsからインストールします。

1
pylang