Как получить все возможные комбинации элементов списка?

У меня есть список из 15 чисел, и мне нужно написать код, который производит все 32 768 комбинаций этих чисел.

Я нашел некоторый код (от Googling), который, по-видимому, делает то, что я ищу, но я нашел код довольно непрозрачным и опасаюсь его использовать. К тому же я чувствую, что должно быть более элегантное решение.

Единственное, что мне приходит в голову, - это просто перебрать десятичные целые числа 1–32768 и преобразовать их в двоичное, а затем использовать двоичное представление в качестве фильтра для выбора подходящих чисел.

Кто-нибудь знает способ лучше? Может быть, с помощью map()?


person Ben    schedule 21.01.2009    source источник
comment
Читатели должны отметить, что вопрос о том, являются ли элементы списка уникальными, является чрезвычайно важным, так как многие алгоритмы будут переоценивать некоторое подмножество (например, 'abccc' - ›['', 'a', 'b', 'c', 'c', 'c', 'ac', 'ac', 'ac', ...]. Простой обходной путь - просто засунуть все элементы в набор до получения их перестановки.   -  person ninjagecko    schedule 14.09.2015
comment
@ninjagecko Использование библиотеки Set неэффективно, поскольку каждая из них в лучшем случае O (n). Таким образом, добавление n функций в набор на самом деле составляет O (n ^ 2)!   -  person SMBiggs    schedule 11.02.2020
comment
При внимательном чтении вопроса кажется, что OP запрашивает PowerSet из своего списка из 15 чисел, а не всех комбинаций. Думаю, именно поэтому ответы можно найти повсюду.   -  person SMBiggs    schedule 11.02.2020
comment
@ Скотт Биггс: ты уверен, что говоришь здесь о Python? Установка вставок и поисков выполняется в среднем за O (1). Они как словари. Они используют хеширование. У Python нет специальной библиотеки наборов (она находится в стандартной библиотеке). Мы вставляем здесь числа, а не функции. (По-прежнему было бы неэффективно использовать память O (2 ^ n); правильным решением для людей, которым нужны комбинации, а не набор мощности, является простая рекурсивная реализация или product и т. Д.)   -  person ninjagecko    schedule 12.02.2020


Ответы (27)


Взгляните на itertools.combinations:

itertools.combinations(iterable, r)

Возвращает r подпоследовательностей элементов из итерируемого ввода.

Комбинации выводятся в порядке лексикографической сортировки. Итак, если входной итерабельный объект отсортирован, комбинационные кортежи будут создаваться в отсортированном порядке.

Начиная с версии 2.6, батарейки идут в комплекте!

person James Brady    schedule 21.01.2009
comment
вы можете просто перечислить все это. list(itertools.combinations(iterable, r)) - person silgon; 14.09.2017
comment
есть ли что-нибудь, что не требует r, то есть комбинаций подпоследовательностей элементов любой длины. - person mLstudent33; 23.05.2020
comment
это очень хорошо и указывало мне на то, что действительно решило мою проблему, а именно itertools.combination_with_replacement. - person user3348949; 16.10.2020

Этот ответ пропустил один аспект: OP запросил ВСЕ комбинации ... а не только комбинации длины "r".

Таким образом, вам придется либо перебрать все длины "L":

import itertools

stuff = [1, 2, 3]
for L in range(0, len(stuff)+1):
    for subset in itertools.combinations(stuff, L):
        print(subset)

Или - если вы хотите выглядеть шикарно (или сломать мозг того, кто читает ваш код после вас) - вы можете сгенерировать цепочку генераторов «комбинаций ()» и перебирать ее:

from itertools import chain, combinations
def all_subsets(ss):
    return chain(*map(lambda x: combinations(ss, x), range(0, len(ss)+1)))

for subset in all_subsets(stuff):
    print(subset)
person Dan H    schedule 05.05.2011
comment
Спасибо за поддержку! За несколько недель, прошедших после того, как я опубликовал ответ выше, я обнаружил, что НАЗВАНИЕ концепции того, что ищет Бен, - это набор мощности исходного набора из 15 предметов. Фактически, пример реализации приведен на стандартной странице документации python itertools: docs.python.org/ библиотека / itertools.html (grep для powerset). - person Dan H; 16.11.2011
comment
Для тех, кто читает так далеко: функция генератора powerset() в разделе рецептов _ 2_ документация проще, потенциально использует меньше памяти и, вероятно, быстрее, чем реализация, показанная здесь. - person martineau; 25.10.2016
comment
Можно ли сгенерировать все комбинации в лексикографическом порядке? - person guik; 04.04.2018
comment
@guik: Я на 99% уверен, что itertools.combinations сохраняет порядок элементов в списках, которые он дает. Таким образом, если входные данные лексически отсортированы, то каждый из выходных данных также будет отсортирован. - person Dan H; 05.04.2018
comment
Да, itertools.combinations генерирует комбинации k среди n в лексикографическом порядке, но не все комбинации до k среди n. powerset генерирует все комбинации до k, но не в лексикографическом порядке, насколько я понимаю: powerset ([1,2]) - ›[(), (1,), (2, ), (1, 2)]. Разве это не должно быть: [(), (1,), (1, 2), (2,)]? - person guik; 05.04.2018
comment
@guik: Я почти уверен, что некоторые из рекурсивных решений здесь делают это. См., Например, авторство darxtrix. stackoverflow.com/a/23743696/701435 - person Dan H; 07.04.2018
comment
Есть ли простой способ исключить запятую после отдельных элементов, как в (1,)? - person ENIAC-6; 18.12.2020
comment
@ ENIAC-6: именно так Python печатает кортежи с одним элементом. (Запятая отсутствует, пока вы не попытаетесь ее распечатать.) Итак, у вас есть варианты: 1: сначала преобразовать элемент в список: print(list(item)) или 2: использовать ",".join(items), чтобы избежать одноэлементных запятых. - person Dan H; 26.12.2020

Вот ленивый однострочник, также использующий itertools:

from itertools import compress, product

def combinations(items):
    return ( set(compress(items,mask)) for mask in product(*[[0,1]]*len(items)) )
    # alternative:                      ...in product([0,1], repeat=len(items)) )

Основная идея этого ответа: есть 2 ^ N комбинаций - столько же, сколько двоичных строк длины N. Для каждой двоичной строки вы выбираете все элементы, соответствующие «1».

items=abc * mask=###
 |
 V
000 -> 
001 ->   c
010 ->  b
011 ->  bc
100 -> a
101 -> a c
110 -> ab
111 -> abc

На что следует обратить внимание:

  • Для этого необходимо, чтобы вы могли вызвать len(...) на items (обходной путь: если items является чем-то вроде итеративного типа генератора, сначала превратите его в список с помощью items=list(_itemsArg))
  • Для этого требуется, чтобы порядок итерации на items не был случайным (обходной путь: не сходите с ума)
  • Для этого требуется, чтобы элементы были уникальными, иначе {2,2,1} и {2,1,1} оба свернутся до {2,1} (обходной путь: используйте collections.Counter в качестве замены для set; это в основном мультимножество ... хотя вам может потребоваться позже использовать tuple(sorted(Counter(...).elements())), если вам нужно он должен быть хешируемым)

Демо

>>> list(combinations(range(4)))
[set(), {3}, {2}, {2, 3}, {1}, {1, 3}, {1, 2}, {1, 2, 3}, {0}, {0, 3}, {0, 2}, {0, 2, 3}, {0, 1}, {0, 1, 3}, {0, 1, 2}, {0, 1, 2, 3}]

>>> list(combinations('abcd'))
[set(), {'d'}, {'c'}, {'c', 'd'}, {'b'}, {'b', 'd'}, {'c', 'b'}, {'c', 'b', 'd'}, {'a'}, {'a', 'd'}, {'a', 'c'}, {'a', 'c', 'd'}, {'a', 'b'}, {'a', 'b', 'd'}, {'a', 'c', 'b'}, {'a', 'c', 'b', 'd'}]
person ninjagecko    schedule 01.07.2011

В комментариях к ответу @Dan H, получившему большое количество голосов, упоминается рецепт powerset() в _ 2_ документация, в том числе от сам Дэн. Однако пока никто не опубликовал его в качестве ответа. Поскольку это, вероятно, один из лучших, если не лучший подход к проблеме - и с учетом небольшая поддержка от другого комментатора, это показано ниже. Функция создает все уникальные комбинации элементов списка любой длины (включая те, которые содержат ноль и все элементы).

Примечание. Если цель несколько отличается, чтобы получить только комбинации уникальных элементов, измените строку s = list(iterable) на s = list(set(iterable)), чтобы исключить любые повторяющиеся элементы. Несмотря на это, тот факт, что iterable в конечном итоге превращается в list, означает, что он будет работать с генераторами (в отличие от некоторых других ответов).

from itertools import chain, combinations

def powerset(iterable):
    "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
    s = list(iterable)  # allows duplicate elements
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

stuff = [1, 2, 3]
for i, combo in enumerate(powerset(stuff), 1):
    print('combo #{}: {}'.format(i, combo))

Выход:

combo #1: ()
combo #2: (1,)
combo #3: (2,)
combo #4: (3,)
combo #5: (1, 2)
combo #6: (1, 3)
combo #7: (2, 3)
combo #8: (1, 2, 3)
person martineau    schedule 06.12.2016
comment
Для чего в первую очередь нужна list() конверсия? - person AMC; 07.12.2019
comment
@Alexander: Чтобы можно было определить длину итерации. - person martineau; 07.12.2019

Вот пример с использованием рекурсии:

>>> import copy
>>> def combinations(target,data):
...     for i in range(len(data)):
...         new_target = copy.copy(target)
...         new_data = copy.copy(data)
...         new_target.append(data[i])
...         new_data = data[i+1:]
...         print new_target
...         combinations(new_target,
...                      new_data)
...                      
... 
>>> target = []
>>> data = ['a','b','c','d']
>>> 
>>> combinations(target,data)
['a']
['a', 'b']
['a', 'b', 'c']
['a', 'b', 'c', 'd']
['a', 'b', 'd']
['a', 'c']
['a', 'c', 'd']
['a', 'd']
['b']
['b', 'c']
['b', 'c', 'd']
['b', 'd']
['c']
['c', 'd']
['d']
person darxtrix    schedule 19.05.2014
comment
Можно ли изменить это так, чтобы вместо печати возвращался список списков? - person James Vickery; 09.11.2017
comment
@JamesVickery да, вы могли бы посмотреть, как создать список вне функции и добавить к нему, или (лучше) сделать функцию генератором, взгляните на ключевое слово yield :) - person Dangercrow; 12.11.2017
comment
new_data = copy.copy(data) - эта строка, насколько я понимаю, лишняя, ни на что не влияет - person Dmitriy Fialkovskiy; 25.10.2018

Этот однострочник дает вам все комбинации (между 0 и n элементами, если исходный список / набор содержит n различных элементов) и использует собственный метод _ 4_:

Python 2

from itertools import combinations

input = ['a', 'b', 'c', 'd']

output = sum([map(list, combinations(input, i)) for i in range(len(input) + 1)], [])

Python 3

from itertools import combinations

input = ['a', 'b', 'c', 'd']

output = sum([list(map(list, combinations(input, i))) for i in range(len(input) + 1)], [])

Результатом будет:

[[],
 ['a'],
 ['b'],
 ['c'],
 ['d'],
 ['a', 'b'],
 ['a', 'c'],
 ['a', 'd'],
 ['b', 'c'],
 ['b', 'd'],
 ['c', 'd'],
 ['a', 'b', 'c'],
 ['a', 'b', 'd'],
 ['a', 'c', 'd'],
 ['b', 'c', 'd'],
 ['a', 'b', 'c', 'd']]

Попробуйте онлайн:

http://ideone.com/COghfX

person Mathieu Rodic    schedule 25.06.2014
comment
Это перестановка - person AdHominem; 28.10.2016
comment
@AdHominem: нет, это не так. Это список всех комбинаций. Перестановки будут включать, например, ['b', 'a']. - person naught101; 06.12.2016
comment
@ 0x48piraj: спасибо, что заметили, поэтому я отредактировал свой ответ! - person Mathieu Rodic; 07.02.2019

Это подход, который можно легко перенести на все языки программирования, поддерживающие рекурсию (без itertools, без yield, без понимания списка):

def combs(a):
    if len(a) == 0:
        return [[]]
    cs = []
    for c in combs(a[1:]):
        cs += [c, c+[a[0]]]
    return cs

>>> combs([1,2,3,4,5])
[[], [1], [2], [2, 1], [3], [3, 1], [3, 2], ..., [5, 4, 3, 2, 1]]
person Jonathan R    schedule 01.02.2019
comment
Ах! Хорошая реализация. Я узнал HEAD = a [0], TAIL = a [1:] из Пролога. Или car = a [0], cdr = a [1:] из Лиспа. Интересно, можно ли здесь использовать мемоизацию ... - person Javier Ruiz; 14.06.2020
comment
Правда. Нарезка списка - это O (k), где k - длина фрагмента. Я думаю, можно было бы ускорить это, выполнив поиск на карте, который сделает его O (1) во всех запусках, кроме первого. Однако обратите внимание, что на эту реализацию не следует ссылаться из-за производительности. Для этого существуют лучшие реализации. Эта реализация предназначена только для простоты и переносимости на большинство других языков. - person Jonathan R; 15.06.2020

Я согласен с Дэном Х. в том, что Бен действительно запрашивал все комбинации. itertools.combinations() не дает всех комбинаций.

Другая проблема заключается в том, что если итерируемый ввод большой, возможно, лучше вернуть генератор вместо всего в списке:

iterable = range(10)
for s in xrange(len(iterable)+1):
  for comb in itertools.combinations(iterable, s):
    yield comb
person HongboZhu    schedule 24.08.2011
comment
Хороший пример. Я люблю генераторы ... и люблю Python за то, что они есть! В этом примере одновременно используется только один объект комбинаций (), и в каждый момент времени получается одна из комбинаций. (Возможно, вы захотите добавить вокруг этого блок def - в качестве примера использования.) Обратите внимание, что моя реализация (с цепочкой (), приведенной выше) не намного хуже: это правда, что она создает все генераторы len (итерируемые) в один раз ... но он НЕ создает сразу все 2 ** len (итерируемые) комбинации, поскольку, насколько я понимаю, цепочка использует первый генератор перед тем, как рисовать из последующих. - person Dan H; 16.11.2011

Вы можете сгенерировать все комбинации списка в Python, используя этот простой код:

import itertools

a = [1,2,3,4]
for i in xrange(0,len(a)+1):
   print list(itertools.combinations(a,i))

Результат будет:

[()]
[(1,), (2,), (3,), (4,)]
[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
[(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]
[(1, 2, 3, 4)]
person saimadhu.polamuri    schedule 17.03.2015
comment
Ошибка в этом коде: не возвращает пустой набор. Может означать xrange (0, ...), но не тестировал. изменить: я отредактировал ваш ответ, чтобы исправить это. - person ninjagecko; 14.09.2015
comment
Прохладный. Я пытался создать доменные имена из названий компаний для очистки сайта, и это помогло мне в этом. - person SleepyBoBos; 03.07.2021

Я подумал, что добавлю эту функцию для тех, кто ищет ответ, без импорта itertools или каких-либо других дополнительных библиотек.

def powerSet(items):
    """
    Power set generator: get all possible combinations of a list’s elements

    Input:
        items is a list
    Output:
        returns 2**n combination lists one at a time using a generator 

    Reference: edx.org 6.00.2x Lecture 2 - Decision Trees and dynamic programming
    """

    N = len(items)
    # enumerate the 2**N possible combinations
    for i in range(2**N):
        combo = []
        for j in range(N):
            # test bit jth of integer i
            if (i >> j) % 2 == 1:
                combo.append(items[j])
        yield combo

Простое использование генератора доходности:

for i in powerSet([1,2,3,4]):
    print (i, ", ",  end="")

Вывод из приведенного выше примера использования:

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

person Community    schedule 20.12.2016
comment
Думаю, это очень изящное решение. - person greentec; 26.03.2019

Вот еще одно решение (однострочное), включающее использование функции itertools.combinations, но здесь мы используем понимание двойного списка (в отличие от цикла for или суммы):

def combs(x):
    return [c for i in range(len(x)+1) for c in combinations(x,i)]

Демо:

>>> combs([1,2,3,4])
[(), 
 (1,), (2,), (3,), (4,), 
 (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4), 
 (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4), 
 (1, 2, 3, 4)]
person ninjagecko    schedule 14.09.2015

from itertools import permutations, combinations


features = ['A', 'B', 'C']
tmp = []
for i in range(len(features)):
    oc = combinations(features, i + 1)
    for c in oc:
        tmp.append(list(c))

выход

[
 ['A'],
 ['B'],
 ['C'],
 ['A', 'B'],
 ['A', 'C'],
 ['B', 'C'],
 ['A', 'B', 'C']
]
person Andrew Li    schedule 23.11.2019
comment
permutations импорт не используется. - person Alex Povel; 18.09.2020

3 функции:

  1. список всех комбинаций из n элементов
  2. список всех комбинаций из n элементов, порядок которых не отличается
  3. все перестановки
import sys

def permutations(a):
    return combinations(a, len(a))

def combinations(a, n):
    if n == 1:
        for x in a:
            yield [x]
    else:
        for i in range(len(a)):
            for x in combinations(a[:i] + a[i+1:], n-1):
                yield [a[i]] + x

def combinationsNoOrder(a, n):
    if n == 1:
        for x in a:
            yield [x]
    else:
        for i in range(len(a)):
            for x in combinationsNoOrder(a[:i], n-1):
                yield [a[i]] + x
    
if __name__ == "__main__":
    for s in combinations(list(map(int, sys.argv[2:])), int(sys.argv[1])):
        print(s)
person Alan Swindells    schedule 03.03.2020
comment
Мне это очень нравится!!! Спасибо!!! Однако комбинаторические функции Python немного странные. В математике функция комбинаций будет вариациями, а комбинацияNoOrder на самом деле является комбинацией. Я предполагаю, что это сбивает с толку людей, пришедших к Python из области математики, как это случилось со мной на этот раз. В любом случае, хорошее решение, большое спасибо за выигрыш! - person Đumić Branislav; 23.04.2020

Вы также можете использовать функцию powerset из отличного < пакет href = "https://pypi.org/project/more-itertools/" rel = "noreferrer"> _ 1_.

from more_itertools import powerset

l = [1,2,3]
list(powerset(l))

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

Мы также можем проверить, что он соответствует требованиям OP

from more_itertools import ilen

assert ilen(powerset(range(15))) == 32_768
person Jarno    schedule 05.05.2020

Ниже приведен «стандартный рекурсивный ответ», аналогичный другому аналогичному ответу https://stackoverflow.com/a/23743696/711085. (На самом деле нам не нужно беспокоиться о нехватке места в стеке, поскольку мы не можем обработать все N! Перестановок.)

Он посещает каждый элемент по очереди и либо берет его, либо покидает его (мы можем напрямую увидеть мощность 2 ^ N из этого алгоритма).

def combs(xs, i=0):
    if i==len(xs):
        yield ()
        return
    for c in combs(xs,i+1):
        yield c
        yield c+(xs[i],)

Демо:

>>> list( combs(range(5)) )
[(), (0,), (1,), (1, 0), (2,), (2, 0), (2, 1), (2, 1, 0), (3,), (3, 0), (3, 1), (3, 1, 0), (3, 2), (3, 2, 0), (3, 2, 1), (3, 2, 1, 0), (4,), (4, 0), (4, 1), (4, 1, 0), (4, 2), (4, 2, 0), (4, 2, 1), (4, 2, 1, 0), (4, 3), (4, 3, 0), (4, 3, 1), (4, 3, 1, 0), (4, 3, 2), (4, 3, 2, 0), (4, 3, 2, 1), (4, 3, 2, 1, 0)]

>>> list(sorted( combs(range(5)), key=len))
[(), 
 (0,), (1,), (2,), (3,), (4,), 
 (1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2), (4, 0), (4, 1), (4, 2), (4, 3), 
 (2, 1, 0), (3, 1, 0), (3, 2, 0), (3, 2, 1), (4, 1, 0), (4, 2, 0), (4, 2, 1), (4, 3, 0), (4, 3, 1), (4, 3, 2), 
 (3, 2, 1, 0), (4, 2, 1, 0), (4, 3, 1, 0), (4, 3, 2, 0), (4, 3, 2, 1), 
 (4, 3, 2, 1, 0)]

>>> len(set(combs(range(5))))
32
person ninjagecko    schedule 13.09.2015

Я знаю, что гораздо практичнее использовать itertools для получения всех комбинаций, но вы можете достичь этого частично с помощью только понимания списка, если вы так захотите, если вы хотите кодировать много

Для комбинаций из двух пар:

lambda l: [(a, b) for i, a in enumerate(l) for b in l[i+1:]]

А для комбинаций из трех пар это так просто:

lambda l: [(a, b, c) for i, a in enumerate(l) for ii, b in enumerate(l[i+1:]) for c in l[i+ii+2:]]

Результат идентичен использованию itertools.combinations:

import itertools
combs_3 = lambda l: [
    (a, b, c) for i, a in enumerate(l) 
    for ii, b in enumerate(l[i+1:]) 
    for c in l[i+ii+2:]
]
data = ((1, 2), 5, "a", None)
print("A:", list(itertools.combinations(data, 3)))
print("B:", combs_3(data))
# A: [((1, 2), 5, 'a'), ((1, 2), 5, None), ((1, 2), 'a', None), (5, 'a', None)]
# B: [((1, 2), 5, 'a'), ((1, 2), 5, None), ((1, 2), 'a', None), (5, 'a', None)]
person Cynadyde    schedule 06.10.2017

Вот две реализации itertools.combinations

Тот, который возвращает список

def combinations(lst, depth, start=0, items=[]):
    if depth <= 0:
        return [items]
    out = []
    for i in range(start, len(lst)):
        out += combinations(lst, depth - 1, i + 1, items + [lst[i]])
    return out

Один возвращает генератор

def combinations(lst, depth, start=0, prepend=[]):
    if depth <= 0:
        yield prepend
    else:
        for i in range(start, len(lst)):
            for c in combinations(lst, depth - 1, i + 1, prepend + [lst[i]]):
                yield c

Обратите внимание, что рекомендуется предоставить им вспомогательную функцию, потому что аргумент prepend является статическим и не меняется при каждом вызове.

print([c for c in combinations([1, 2, 3, 4], 3)])
# [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]

# get a hold of prepend
prepend = [c for c in combinations([], -1)][0]
prepend.append(None)

print([c for c in combinations([1, 2, 3, 4], 3)])
# [[None, 1, 2, 3], [None, 1, 2, 4], [None, 1, 3, 4], [None, 2, 3, 4]]

Это очень поверхностный случай, но лучше перестраховаться, чем потом сожалеть

person Modar    schedule 06.11.2017

Как насчет этого ... использовала строку вместо списка, но то же самое ... строку можно рассматривать как список в Python:

def comb(s, res):
    if not s: return
    res.add(s)
    for i in range(0, len(s)):
        t = s[0:i] + s[i + 1:]
        comb(t, res)

res = set()
comb('game', res) 

print(res)
person Apurva Singh    schedule 17.12.2017

Комбинация от itertools

import itertools
col_names = ["aa","bb", "cc", "dd"]
all_combinations = itertools.chain(*[itertools.combinations(col_names,i+1) for i,_ in enumerate(col_names)])
print(list(all_combinations))
person Abhishek    schedule 19.12.2017

Этот код использует простой алгоритм с вложенными списками ...

# FUNCTION getCombos: To generate all combos of an input list, consider the following sets of nested lists...
#
#           [ [ [] ] ]
#           [ [ [] ], [ [A] ] ]
#           [ [ [] ], [ [A],[B] ],         [ [A,B] ] ]
#           [ [ [] ], [ [A],[B],[C] ],     [ [A,B],[A,C],[B,C] ],                   [ [A,B,C] ] ]
#           [ [ [] ], [ [A],[B],[C],[D] ], [ [A,B],[A,C],[B,C],[A,D],[B,D],[C,D] ], [ [A,B,C],[A,B,D],[A,C,D],[B,C,D] ], [ [A,B,C,D] ] ]
#
#  There is a set of lists for each number of items that will occur in a combo (including an empty set).
#  For each additional item, begin at the back of the list by adding an empty list, then taking the set of
#  lists in the previous column (e.g., in the last list, for sets of 3 items you take the existing set of
#  3-item lists and append to it additional lists created by appending the item (4) to the lists in the
#  next smallest item count set. In this case, for the three sets of 2-items in the previous list. Repeat
#  for each set of lists back to the initial list containing just the empty list.
#

def getCombos(listIn = ['A','B','C','D','E','F'] ):
    listCombos = [ [ [] ] ]     # list of lists of combos, seeded with a list containing only the empty list
    listSimple = []             # list to contain the final returned list of items (e.g., characters)

    for item in listIn:
        listCombos.append([])   # append an emtpy list to the end for each new item added
        for index in xrange(len(listCombos)-1, 0, -1):  # set the index range to work through the list
            for listPrev in listCombos[index-1]:        # retrieve the lists from the previous column
                listCur = listPrev[:]                   # create a new temporary list object to update
                listCur.append(item)                    # add the item to the previous list to make it current
                listCombos[index].append(listCur)       # list length and append it to the current list

                itemCombo = ''                          # Create a str to concatenate list items into a str
                for item in listCur:                    # concatenate the members of the lists to create
                    itemCombo += item                   # create a string of items
                listSimple.append(itemCombo)            # add to the final output list

    return [listSimple, listCombos]
# END getCombos()
person TiPS    schedule 01.05.2015
comment
Похоже, что этот код возвращает [listOfCombinations, listOfCombinationsGroupedBySize]. К сожалению, при запуске с демонстрационным вводом он дает 63 элемента, а не 64; похоже, отсутствует пустой набор (в данном случае пустая строка ""). - person ninjagecko; 14.09.2015

Без использования itertools:

def combine(inp):
    return combine_helper(inp, [], [])


def combine_helper(inp, temp, ans):
    for i in range(len(inp)):
        current = inp[i]
        remaining = inp[i + 1:]
        temp.append(current)
        ans.append(tuple(temp))
        combine_helper(remaining, temp, ans)
        temp.pop()
    return ans


print(combine(['a', 'b', 'c', 'd']))
person Pradeep Vairamani    schedule 22.10.2017

Без itertools в Python 3 вы могли бы сделать что-то вроде этого:

def combinations(arr, carry):
    for i in range(len(arr)):
        yield carry + arr[i]
        yield from combinations(arr[i + 1:], carry + arr[i])

где изначально carry = "".

person Laurynas Tamulevičius    schedule 12.10.2018

Это моя реализация

def get_combinations(list_of_things):
"""gets every combination of things in a list returned as a list of lists

Should be read : add all combinations of a certain size to the end of a list for every possible size in the
the list_of_things.

"""
list_of_combinations = [list(combinations_of_a_certain_size)
                        for possible_size_of_combinations in range(1,  len(list_of_things))
                        for combinations_of_a_certain_size in itertools.combinations(list_of_things,
                                                                                     possible_size_of_combinations)]
return list_of_combinations
person Andres Ulloa    schedule 05.02.2017
comment
Что ваша реализация решает лучше, чем предыдущие реализации, размещенные здесь. - person user1767754; 02.01.2018

Использование понимания списка:

def selfCombine( list2Combine, length ):
    listCombined = str( ['list2Combine[i' + str( i ) + ']' for i in range( length )] ).replace( "'", '' ) \
                     + 'for i0 in range(len( list2Combine ) )'
    if length > 1:
        listCombined += str( [' for i' + str( i ) + ' in range( i' + str( i - 1 ) + ', len( list2Combine ) )' for i in range( 1, length )] )\
            .replace( "', '", ' ' )\
            .replace( "['", '' )\
            .replace( "']", '' )

    listCombined = '[' + listCombined + ']'
    listCombined = eval( listCombined )

    return listCombined

list2Combine = ['A', 'B', 'C']
listCombined = selfCombine( list2Combine, 2 )

Результат будет:

['A', 'A']
['A', 'B']
['A', 'C']
['B', 'B']
['B', 'C']
['C', 'C']
person zmk    schedule 21.08.2011
comment
Это предложение состоит в том, чтобы изменить последовательность строк для создания наборов?!?! Святая ворона .... И: это не возврат powerset, а что-то вроде комбинаций_with_replacement (). (См. docs.python.org/library/) - person Dan H; 16.11.2011
comment
Это действительно то же самое, что и comb_with_replacement (), но, по крайней мере, на моем ящике это работает немного быстрее, чем itertools. Что сказать, мне нравится составление списков. - person zmk; 25.11.2011
comment
Спасибо за ответ! А как насчет создания списка в сочетании с перевернутыми списками, такими как ['A', 'A'], ['A', 'B'], ['A', 'C'], ['B', 'A'], [ 'B', 'B'], ['B', 'C'], ['C', 'A'], ['C', 'B'] и ['C', 'C'], которые включают все? - person Karyo; 19.03.2015
comment
Очень интересно, но мой питон не совсем разбирается в тонкостях. Есть ли что-то особенное в использовании listCombined в разных областях и в том факте, что цикл for находится в одной строке? Я безуспешно пытаюсь перенести это на Java. - person SMBiggs; 11.02.2020

Я опаздываю на вечеринку, но хотел бы поделиться решением, которое я нашел для той же проблемы: в частности, я искал последовательные комбинации, поэтому для STAR мне нужны были STAR, TA, AR, но не SR.

lst = [S, T, A, R]
lstCombos = []
for Length in range(0,len(lst)+1):
    for i in lst:
        lstCombos.append(lst[lst.index(i):lst.index(i)+Length])

Дубликаты могут быть отфильтрованы добавлением дополнительной строки if перед последней строкой:

lst = [S, T, A, R]
lstCombos = []
for Length in range(0,len(lst)+1):
    for i in lst:
         if not lst[lst.index(i):lst.index(i)+Length]) in lstCombos:
             lstCombos.append(lst[lst.index(i):lst.index(i)+Length])

Если по какой-то причине это возвращает пустые списки на выходе, что случилось со мной, я добавил:

for subList in lstCombos:
    if subList = '':
         lstCombos.remove(subList)
person yip_yip    schedule 30.10.2020

Как указано в документации

def combinations(iterable, r):
    # combinations('ABCD', 2) --> AB AC AD BC BD CD
    # combinations(range(4), 3) --> 012 013 023 123
    pool = tuple(iterable)
    n = len(pool)
    if r > n:
        return
    indices = list(range(r))
    yield tuple(pool[i] for i in indices)
    while True:
        for i in reversed(range(r)):
            if indices[i] != i + n - r:
                break
        else:
            return
        indices[i] += 1
        for j in range(i+1, r):
            indices[j] = indices[j-1] + 1
        yield tuple(pool[i] for i in indices)


x = [2, 3, 4, 5, 1, 6, 4, 7, 8, 3, 9]
for i in combinations(x, 2):
    print i
person Anoop    schedule 07.05.2016
comment
Если я прав, это точный код, скопированный из документации Python [docs.python. org / 3.6 / library / itertools.html]. Если да, пожалуйста, сделайте ссылку на источник. - person GabrielChu; 18.12.2017
comment
интересный подход - person pelos; 27.11.2018
comment
@GabrielChu только что это исправил. Формат тоже был неправильным. - person Tiago Martins Peres 李大仁; 28.10.2020

Если кто-то ищет перевернутый список, как я:

stuff = [1, 2, 3, 4]

def reverse(bla, y):
    for subset in itertools.combinations(bla, len(bla)-y):
        print list(subset)
    if y != len(bla):
        y += 1
        reverse(bla, y)

reverse(stuff, 1)
person Expat C    schedule 04.12.2017