У меня есть список из 15 чисел, и мне нужно написать код, который производит все 32 768 комбинаций этих чисел.
Я нашел какой-то код (от Googling), который, по-видимому, делает то, что я ищу, но я нашел код довольно непрозрачным и опасаюсь его использовать. К тому же я чувствую, что должно быть более элегантное решение.
Единственное, что мне приходит в голову, - это просто перебрать десятичные целые числа 1–32768 и преобразовать их в двоичное, а затем использовать двоичное представление в качестве фильтра для выбора подходящих чисел.
Кто-нибудь знает способ лучше? Может быть, с использованием map()?
@ninjagecko Использование библиотеки Set неэффективно, поскольку каждая из них в лучшем случае O (n). Таким образом, добавление n функций в набор на самом деле составляет O (n ^ 2)!
При внимательном чтении вопроса кажется, что OP запрашивает PowerSet своего списка из 15 номеров, а не всех комбинаций. Думаю, именно поэтому ответы можно найти повсюду.
@ Скотт Биггс: ты уверен, что говоришь здесь о Python? Установка вставок и поисков выполняется в среднем за O (1). Они как словари. Они используют хеширование. У Python нет специальной библиотеки наборов (она находится в стандартной библиотеке). Мы вставляем здесь числа, а не функции. (По-прежнему было бы неэффективно использовать память O (2 ^ n); правильным решением для людей, которым нужны комбинации, а не набор мощности, является простая рекурсивная реализация или product и т. д.)






Взгляните на itertools.combinations:
itertools.combinations(iterable, r)Return r length subsequences of elements from the input iterable.
Combinations are emitted in lexicographic sort order. So, if the input iterable is sorted, the combination tuples will be produced in sorted order.
Начиная с версии 2.6, батарейки идут в комплекте!
вы можете просто перечислить все это. list(itertools.combinations(iterable, r))
есть ли что-нибудь, что не требует r, то есть комбинации подпоследовательностей элементов любой длины.
это очень хорошо и указывало мне на то, что действительно решило мою проблему, а именно на itertools.combination_with_replacement.
Этот ответ упустил один аспект: 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)
Спасибо за поддержку! За несколько недель, прошедших после того, как я отправил ответ выше, я обнаружил, что НАЗВАНИЕ концепции того, что ищет Бен, является «powerset» исходного набора из 15 предметов. Фактически, пример реализации приведен на стандартной странице документа python "itertools": docs.python.org/library/itertools.html (grep для "powerset").
Для тех, кто читает это далеко: функция генератора powerset() в разделе рецептов itertools документация проще, потенциально использует меньше памяти и, вероятно, быстрее, чем реализация, показанная здесь.
Можно ли сгенерировать все комбинации в лексикографическом порядке?
@guik: Я на 99% уверен, что itertools.combinations сохраняет порядок элементов в списках, которые он выдает. Таким образом, если входные данные лексически отсортированы, то каждый из выходов также будет отсортирован.
Да, itertools.combinations генерирует комбинации k среди n в лексикографическом порядке, но не все комбинации вплоть до k среди n. powerset генерирует все комбинации вплоть до k, но не в лексикографическом порядке, насколько я понимаю: powerset ([1,2]) -> [(), (1,), (2,), (1, 2)] . Разве это не должно быть: [(), (1,), (1, 2), (2,)]?
@guik: Я почти уверен, что некоторые из рекурсивных решений здесь делают это. См., Например, авторство darxtrix. stackoverflow.com/a/23743696/701435
Есть ли простой способ исключить запятую после отдельных элементов, как в (1,)?
@ ENIAC-6: именно так Python печатает кортежи с одним элементом. (Запятая отсутствует, пока вы не попытаетесь ее распечатать.) Итак, у вас есть варианты: 1: сначала преобразовать элемент в список: print(list(item)) или 2: использовать ",".join(items), чтобы избежать одноэлементных запятых.
Вот ленивый однострочник, также использующий 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'}]
Использование понимания списка:
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']
Это предложение состоит в том, чтобы изменить последовательность строк для создания наборов?!?! Святая ворона .... И: это не возврат powerset, а что-то вроде комбинаций_with_replacement (). (См. docs.python.org/library/…)
Это действительно то же самое, что и комбинация_with_replacement (), но, по крайней мере, на моем компьютере это работает немного быстрее, чем itertools. Что сказать, мне нравится составление списков.
Спасибо за ответ! А как насчет создания списка в сочетании с перевернутыми списками, такими как ['A', 'A'], ['A', 'B'], ['A', 'C'], ['B', 'A'], [ 'B', 'B'], ['B', 'C'], ['C', 'A'], ['C', 'B'] и ['C', 'C'], которые включают все?
Очень интересно, но мой питон не совсем разбирается в тонкостях. Есть ли что-то особенное в использовании listCombined в разных областях и в том, что цикл for находится в одной строке? Я безуспешно пытаюсь перенести это на Java.
Я согласен с Дэном Х. в том, что Бен действительно просил комбинации все. itertools.combinations() не дает всех комбинаций.
Другая проблема заключается в том, что если итерируемый ввод большой, возможно, лучше вернуть генератор вместо всего в списке:
iterable = range(10)
for s in xrange(len(iterable)+1):
for comb in itertools.combinations(iterable, s):
yield comb
Хороший пример. Я люблю генераторы ... и люблю Python за то, что они есть! В этом примере одновременно используется только один объект комбинаций (), и в каждый момент времени получается одна из комбинаций. (Возможно, вы захотите добавить вокруг этого блок def - в качестве примера использования.) Обратите внимание, что моя реализация (с цепочкой (), приведенной выше) не намного хуже: это правда, что она создает все len (итерируемые) генераторы в один раз ... но он НЕ создает сразу все 2 ** len (итерируемые) комбинации, поскольку, насколько я понимаю, цепочка "использует" первый генератор перед отрисовкой из последующих.
Вот пример с использованием рекурсии:
>>> 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']
Можно ли изменить это так, чтобы он возвращал список списков вместо печати?
@JamesVickery да, вы могли бы посмотреть, как создать список вне функции и добавить к нему, или (лучше) сделать функцию генератором, взгляните на ключевое слово yield :)
new_data = copy.copy(data) - эта строка, насколько я понимаю, лишняя, ни на что не влияет
Этот однострочный файл дает вам все комбинации (между элементами 0 и n, если исходный список / набор содержит отдельные элементы n) и использует собственный метод itertools.combinations:
from itertools import combinations
input = ['a', 'b', 'c', 'd']
output = sum([map(list, combinations(input, i)) for i in range(len(input) + 1)], [])
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']]
Попробуйте онлайн:
Это перестановка
@AdHominem: нет, это не так. Это список всех комбинаций. Перестановки могут включать, например, ['b', 'a'].
TypeError: can only concatenate list (not "map") to list@ 0x48piraj: спасибо, что заметили, поэтому я отредактировал свой ответ!
Вы можете сгенерировать все комбинации списка в 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)]
Ошибка в этом коде: не возвращает пустой набор. Может означать xrange (0, ...), но не тестировал. редактировать: Я отредактировал ваш ответ, чтобы исправить это.
Этот код использует простой алгоритм с вложенными списками ...
# 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()
Кажется, этот код возвращает [listOfCombinations, listOfCombinationsGroupedBySize]. К сожалению, при запуске с демонстрационным вводом он дает 63 элемента, а не 64; похоже, отсутствует пустой набор (в данном случае пустая строка "").
Ниже приведен «стандартный рекурсивный ответ», похожий на другой аналогичный ответ 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
Вот еще одно решение (однострочное), включающее использование функции 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)]
Как указано в документация
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
Если я прав, это точный код, скопированный из документации Python [docs.python.org/3.6/library/itertools.html]. Если да, пожалуйста, сделайте ссылку на источник.
интересный подход
@GabrielChu только что исправил. Формат тоже был неправильным.
В комментариях под отвечать, получившим большое количество голосов от @Dan H, упоминается рецепт powerset() в itertools документация, включая рецепт Сам Дэн. тем не мение, пока никто в ответ не выложил. Поскольку это, вероятно, один из лучших, если не лучший подход к проблеме - и учитывая небольшая поддержка от другого комментатора, он показан ниже. Функция создает уникальные комбинации все элементов списка возможной длины каждый (включая те, которые содержат ноль и все элементы).
Примечание: Если цель несколько отличается, чтобы получить только комбинации уникальных элементов, измените строку 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)
Для чего в первую очередь нужно преобразование list()?
@Alexander: Чтобы можно было определить длину итерации.
Я подумал, что добавлю эту функцию для тех, кто ищет ответ, без импорта 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] ,
Думаю, это очень изящное решение.
Это моя реализация
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
Что ваша реализация решает лучше, чем предыдущие реализации, размещенные здесь.
Я знаю, что гораздо практичнее использовать 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)]
Без использования 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']))
Вот две реализации 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]]
Это очень поверхностный случай, но лучше перестраховаться, чем потом сожалеть
Если кто-то ищет перевернутый список, как я:
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)
Как насчет этого ... использовала строку вместо списка, но то же самое ... строку можно рассматривать как список в 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)
Комбинация от 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))
Без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 = "".
Это подход, который можно легко перенести на все языки программирования, поддерживающие рекурсию (нет инструментов itertools, нет выхода, нет понимания списка):
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]]
Ах! Хорошая реализация. Я узнал HEAD = a [0], TAIL = a [1:] из Пролога. Или car = a [0], cdr = a [1:] из Лиспа. Интересно, можно ли здесь использовать мемоизацию ...
Правда. Нарезка списка - это O (k), где k - длина фрагмента. Я думаю, можно было бы ускорить это, выполнив поиск на карте, который сделает его O (1) во всех запусках, кроме первого. Однако обратите внимание, что на эту реализацию не следует ссылаться для оценки производительности. Для этого существуют лучшие реализации. Эта реализация предназначена только для простоты и переносимости на большинство других языков.
flag = 0
requiredCals =12
from itertools import chain, combinations
def powerset(iterable):
s = list(iterable) # allows duplicate elements
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
stuff = [2,9,5,1,6]
for i, combo in enumerate(powerset(stuff), 1):
if (len(combo)>0):
#print(combo , sum(combo))
if (sum(combo)== requiredCals):
flag = 1
break
if (flag==1):
print('True')
else:
print('else')
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']
]
Импорт permutations не используется.
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)
Мне это очень нравится!!! Спасибо!!! Однако комбинаторические функции Python немного странные. В математике функция «комбинаций» будет вариациями, а «комбинацияNoOrder» - фактически комбинациями. Думаю, это сбивает с толку людей, пришедших к Python из области математики, как это случилось со мной на этот раз. В любом случае, хорошее решение, большое спасибо за выигрыш!
Вы также можете использовать функцию powerset из отличного пакета more_itertools.
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
Я опаздываю на вечеринку, но хотел бы поделиться решением, которое я нашел для той же проблемы: В частности, я искал последовательные комбинации, поэтому для «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)
Читатели должны отметить, что то, являются ли элементы списка уникальный, является чрезвычайно важным соображением, так как многие алгоритмы затем будут пересчитывать некоторое подмножество (например, 'abccc' -> ['', 'a', 'b', 'c', 'c' , 'c', 'ac', 'ac', 'ac', ...]. Простой обходной путь - просто засунуть все элементы в набор перед, получив их перестановки.