在没有两个连续相等元素的python中重复排列

我需要一个函数来生成所有的排列,重复一个iterable,其中两个连续的元素必须是不同的;例如

f([0,1],3).sort()==[(0,1,0),(1,0,1)]
#or
f([0,1],3).sort()==[[0,1,0],[1,0,1]]
#I don't need the elements in the list to be sorted.
#the elements of the return can be tuples or lists, it doesn't change anything

不幸的是,itertools.permutation对我需要的东西不起作用(迭代中的每个元素在返回中都存在一次或没有)

我尝试过一堆定义;首先,来自itertools.product(iterable,repeat = r)输入的过滤元素,但对于我需要的东西来说太慢了.

from itertools import product
def crp0(iterable,r):
l=[]
for f in product(iterable,repeat=r):
    #print(f)
    b=True
    last=None #supposing no element of the iterable is None, which is fine for me
    for element in f:
        if element==last:
            b=False
            break
        last=element
    if b: l.append(f)
return l

其次,我试图为循环构建r,一个在另一个内部(其中r是排列的类,在数学中表示为k).

def crp2(iterable,r):
    a=list(range(0,r))
    s="\n"
    tab="    " #4 spaces
    l=[]
    for i in a:
        s+=(2*i*tab+"for a["+str(i)+"] in iterable:\n"+
        (2*i+1)*tab+"if "+str(i)+"==0 or a["+str(i)+"]!=a["+str(i-1)+"]:\n")
    s+=(2*i+2)*tab+"l.append(a.copy())"
    exec(s)
    return l

我知道,你不需要记住我:exec是丑陋的,exec可能很危险,exec也不容易阅读……我知道.
为了更好地理解这个功能,我建议你用exec替换exec(s).

我给你一个crp([0,1],2)的exec内部字符串的例子:

for a[0] in iterable:
    if 0==0 or a[0]!=a[-1]:
        for a[1] in iterable:
            if 1==0 or a[1]!=a[0]:
                l.append(a.copy())

但是,除了使用exec之外,我还需要更好的函数,因为crp2仍然太慢(即使速度比crp0快);有没有办法用r重新创建代码而不使用exec?还有其他方法可以做我需要的吗?

最佳答案
您可以将序列准备两半,然后预处理后半部分以找到兼容的选项.

def crp2(I,r):
    r0=r//2
    r1=r-r0
    A=crp0(I,r0) # Prepare first half sequences
    B=crp0(I,r1) # Prepare second half sequences
    D = {} # Dictionary showing compatible second half sequences for each token 
    for i in I:
        D[i] = [b for b in B if b[0]!=i]
    return [a+b for a in A for b in D[a[-1]]]

在使用iterable = [0,1,2]和r = 15的测试中,我发现这种方法比使用crp0快一百倍.

转载注明原文:在没有两个连续相等元素的python中重复排列 - 代码日志