我正在尝试创建一个接收元素列表的函数,并递归返回包含该列表的所有排列(长度为r)的列表。但是,如果列表中有-1,则应该可以重复。
例如,对于r = 2的列表[0,-1,2],我希望返回[0,-1],[-1,0],[0,2],[2,0] ,[-1,2],[2,-1]和[-1,-1]。
到目前为止,这是我的功能:
def permutations(i, iterable, used, current, comboList, r):
if (i == len(iterable):
return
if (len(current) == r):
comboList.append(current)
print current
return
elif (used[i] != 1):
current.append(iterable[i])
if (iterable[i][0] != -1):
used[i] = 1
for j in range(0, len(iterable)):
permutations(j+1, iterable, used, current, comboList, r)
used[i] = 0
return comboList
正如您所看到的,我错误地尝试使用“访问列表”来跟踪列表中的哪些元素已被访问过。
答案 0 :(得分:1)
可能有一种更简洁的方式,但这类似完全未经测试的代码:
def apply_mask(mask, perm):
return [perm.pop() if m else -1 for m in mask]
def permutations(iterable, r):
if -1 not in iterable:
# easy case
return map(list, itertools.permutations(iterable, r)))
iterable = [x for x in iterable if x != -1]
def iter_values():
for mask in itertools.product((True, False), repeat=r):
for perm in itertools.permutations(iterable, sum(mask)):
yield apply_mask(mask, list(perm))
return list(iter_values())
也就是说:首先迭代所有可能的“掩码”,其中掩码告诉您哪些元素将包含-1,哪些元素将包含另一个值。然后,对于每个掩码,迭代“其他值”的所有排列。最后,使用apply_mask
将值和-1s插入结果中的正确位置。
答案 1 :(得分:0)
利用itertools.permutations
。你(显然)想要使用任意数量-1的排列,以及可能的其他元素;但你想丢弃重复项。
我们可以通过简单地提供与我们选择的元素一样多的-1来允许任意数量的-1。
我们可以使用套装来丢弃重复项。
import itertools
def unique_permutations_with_negative_ones(iterable, size):
# make a copy for inspection and modification.
candidates = tuple(iterable)
if -1 in candidates:
# ensure enough -1s.
candidates += ((-1,) * (size - candidates.count(-1)))
return set(itertools.permutations(candidates, size))
我们试一试:
>>> unique_permutations_with_negative_ones((0, -1, 2), 2)
{(2, -1), (-1, 0), (-1, 2), (2, 0), (-1, -1), (0, -1), (0, 2)}