Я пытаюсь создать все возможные комбинации между двумя списками A и B в python с несколькими ограничениями. A и B чередуются с выбором значений, всегда выбирает сначала. A и B могут иметь перекрывающиеся значения. Если A уже выбрал значение, B не может выбрать его, и наоборот.
Оба списка не должны быть одинаковой длины. Если в одном списке нет доступных значений, то я прекращаю генерировать комбинации
Также элементы, выбранные каждым, должны быть в порядке возрастания, т.е. A[1] < A[2] <.... A[n]
и B[1] < B[2] <.... B[n]
где A[i]
и B[i]
- элемент i
-th, выбранный соответственно A и B
Пример:
A = [1, 2, 3, 4]
B = [2, 5]
Решение, в котором я нуждаюсь
(1), (2), (3), (4),
(1,2), (1,5), (2,5), (3,2), (3,5), (4,2), (4,5),
(1,2,3), (1,2,4), (3,2,4), (1,5,2), (1,5,3), (1,5,4), (2,5,3), (2,5,4), (3,5,4),
(1,2,3,5), (1,2,4,5), (3,2,4,5)
(1,2,3,5,4)
Я считаю, что itertools в python могут быть полезны для этого, но я действительно не понял, как реализовать его для этого случая.
На данный момент я так решаю:
A = [1, 2, 3, 4]
B = [2, 5]
A_set = set(A)
B_set = set(b)
#Append both sets
C = A.union(B)
for L in range(len(C), 0, -1):
for subset in itertools.combinations(C, L):
#Check if subset meets constraints and print it if it does
Как отмечено в комментариях, это, вероятно, слишком специфично, чтобы его можно было легко решить с помощью itertools, и вместо этого вы должны использовать рекурсивную (генераторную) функцию. Просто выберите следующий элемент из того списка, в котором он находится, отслеживая уже выбранные элементы и рекурсивный вызов функции снова, свопинг и сокращение списков и добавление элемента в набор выбранных элементов, пока вы не получите требуемый число.
Что-то вроде этого (это может быть улучшено путем добавления параметров для текущего индекса в обоих списках вместо фактического отсечения списков для рекурсивных вызовов):
def solve(n, lst1, lst2, selected):
if n == 0:
yield []
elif lst1:
for i, x in enumerate(lst1):
if x not in selected:
selected.add(x)
for rest in solve(n-1, lst2, lst1[i+1:], selected):
yield [x] + rest
selected.remove(x)
Или немного конденсировано:
def solve(n, lst1, lst2, selected):
if n == 0:
yield []
elif lst1:
yield from ([x] + rest for i, x in enumerate(lst1) if x not in selected
for rest in solve(n-1, lst2, lst1[i+1:], selected.union({x})))
Пример:
A = [1, 2, 3, 4]
B = [2, 5]
result = [res for n in range(1, len(A)+len(B)+1) for res in solve(n, A, B, set())]
В result
:
[[1], [2], [3], [4],
[1, 2], [1, 5], [2, 5], [3, 2], [3, 5], [4, 2], [4, 5],
[1, 2, 3], [1, 2, 4], [1, 5, 2], [1, 5, 3], [1, 5, 4], [2, 5, 3], [2, 5, 4], [3, 2, 4], [3, 5, 4],
[1, 2, 3, 5], [1, 2, 4, 5], [3, 2, 4, 5],
[1, 2, 3, 5, 4]]