You can use a recursive function with a generator:
def full_length(d):
return sum(1 if not isinstance(i, list) else full_length(i) for i in d)
def semi_combos(d, current=[]):
if len(current) == len(x) - 1:
yield current
else:
for i in d:
if len(set(current+[i])) == len(current)+1:
yield from semi_combos(d, current+[i])
def remainder_combos(d, _target, current = []):
if full_length(current)+len(_target) == len(x):
yield [_target, *current]
for i in d:
if i not in _target and i not in current:
yield from remainder_combos(d, _target, current+[i])
for x in [['a', 'b', 'c'], ['a', 'b', 'c', 'd']]:
print([b for i in semi_combos(x) for b in list(remainder_combos(x, i))])
Output:
[[['a', 'b'], 'c'], [['a', 'c'], 'b'], [['b', 'a'], 'c'], [['b', 'c'], 'a'], [['c', 'a'], 'b'], [['c', 'b'], 'a']]
[[['a', 'b', 'c'], 'd'], [['a', 'b', 'd'], 'c'], [['a', 'c', 'b'], 'd'], [['a', 'c', 'd'], 'b'], [['a', 'd', 'b'], 'c'], [['a', 'd', 'c'], 'b'], [['b', 'a', 'c'], 'd'], [['b', 'a', 'd'], 'c'], [['b', 'c', 'a'], 'd'], [['b', 'c', 'd'], 'a'], [['b', 'd', 'a'], 'c'], [['b', 'd', 'c'], 'a'], [['c', 'a', 'b'], 'd'], [['c', 'a', 'd'], 'b'], [['c', 'b', 'a'], 'd'], [['c', 'b', 'd'], 'a'], [['c', 'd', 'a'], 'b'], [['c', 'd', 'b'], 'a'], [['d', 'a', 'b'], 'c'], [['d', 'a', 'c'], 'b'], [['d', 'b', 'a'], 'c'], [['d', 'b', 'c'], 'a'], [['d', 'c', 'a'], 'b'], [['d', 'c', 'b'], 'a']]