繁体   English   中英

所有排列的列表,但没有相反的数字

[英]List of all permutations but without opposite numbers

我需要创建一个所有排列的列表,但不包括那些符号变化相同的排列。

例如,从序列

[-2, -1, 1, 2]

我会得到这样的所有排列:

[-2, -1], [-2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2], [2, -1], [2, 1]

目前我使用以下代码:

permutation_items = []
permutations = itertools.permutations(range_items, items)
permutation_item = list(permutations)

例如, range_items = [-2, -1, 1, 2]items = 2

然后消除我使用的所有相反的重复

for element in permutation_items:
    flag=0
    for j in element:
        if ((j in element) & ((j*-1) in element)):
            flag = 1
            break
    if flag == 0:
        all_solutions.append(element)

我认为这不是最好的方法,因为首先我创建一个包含所有排列的列表然后我删除那些我不想要的,你能建议一个更好的方法吗? 另外因为如果我需要创建一个包含10个或更多数字的排列列表,它就变得非常大......

你认为这些尺寸会有问题吗?

请注意:有了这些排列,我需要做进一步的操作(我需要找到给出所有可能的数字对的最小排列数),所以我认为我需要将它们存储在变量中,也因为在我的结尾处算法我需要将结果存储在一个文件中。

...好吧,你的回答非常好,我喜欢你的兴趣...现在,如果我使用我的变量'range_items'列出30个元素(正面和负面),代码使用的时间非常大,我想问你一个多线程的解决方案(所以我可以在具有许多内核的集群中加载代码)......是否可行?

您基本上是在询问如何组合permutationproduct 以下比拒绝更有效(也更简单):您只生成一次所有排列,然后旋转符号。 它在时间O(N!)和空间O(1)方面是渐近最优的:

def plusAndMinusPermutations(items):
    for p in permutations(items):
        for signs in product([-1,1], repeat=len(items)):
            yield [a*sign for a,sign in zip(p,signs)]

(使用itertools作为OP)

演示:

>>> list( plusAndMinusPermutations([1,2]) )
[
 [-1, -2], 
 [-1, 2], 
 [1, -2],
 [1, 2],
 [-2, -1],
 [-2, 1],
 [2, -1],
 [2, 1]
]

这通过factorial(N)因子更有效! (假设你使用它的长度大于2)

或者,我们可以按相反的顺序组合它们(如果你愿意,可以将地图list映射到元组上):

def plusAndMinusPermutations(items):
    for signed in product(*[[-a,a] for a in items]):
        for p in permutations(signed):
            yield p

>>> list( plusAndMinusPermutations([1,2]) )
[
 (-1, -2), 
 (-2, -1), 
 (-1, 2), 
 (2, -1), 
 (1, -2), 
 (-2, 1), 
 (1, 2), 
 (2, 1)
]

编辑以响应OP编辑:

我需要找到给出所有可能的数字对的最小排列数 --OP

我不确定这是什么意思,但根据你的措辞,你几乎肯定不需要做任何这些。 只需使用现有方法强制解决0到10之间的数字问题,然后将结果输入http://oeis.org/ ,您可能会找到一个明确的公式。

以下使用与代码相同的拒绝方法,但效率更高:

(s for s in itertools.permutations(l, 2) if len(set(map(abs, s))) == len(s))

其中l是序列。

唯一棘手的一点是len(set(map(abs, s))) == len(s) 它将置换的所有元素的绝对值放入集合中,并确保集合具有与置换相同的大小。

为了使速度更快,您可以使用置换的长度替换len(s)在上面的示例中为2 )。

我能想到的唯一算法改进是从原始序列中删除重复的数字。 这对你来说是否很重要取决于你是否想要首先重复一遍。

我想了一下,我想你会喜欢这个:

from collections import defaultdict
from itertools import permutations, product

def make_groups(seq):
    found = defaultdict(set)
    for num in seq:
        found[abs(num)].add(num)
    return [list(v) for v in found.itervalues()]

def selective_permutations(seq, r=None):
    for g in permutations(make_groups(seq), r):
        for p in product(*g):
            yield p

它需要你的输入序列 - 例如[-2, -1, 0, 1, 2] - 并通过互斥值对它进行分组 - 所以[[-2, 2], [-1, 1], [0]]

然后它会在组上运行permutations - 例如,你会得到[[-2, 2], [-1, 1]] - [[-2, 2], [-1, 1]] - 然后对结果组运行product ,产生[[-2, -1], [-2, 1], [2, -1], [2, 1]] ,这是我们正在寻找的。

它尊重r参数(对于序列长度),并在平衡和非平衡序列上执行最佳有效工作 - 例如:

for p in selective_permutations([-3,-2,1,2], 2):
    print p

结果是

(1, 2)
(1, -2)
(1, -3)
(2, 1)
(-2, 1)
(2, -3)
(-2, -3)
(-3, 1)
(-3, 2)
(-3, -2)

无需丢弃任何组合。

希望有所帮助! ;-)

假设您只需要成对的数字(如果不是,您必须对递归执行某些操作),并且序列中没有相同的数字

def make_perm(sequens):
    perm_s = []
    for e1 in sequens:
        for e2 in sequens:
            if abs(e1) != abs(e2):
               perm_s += [[e1,e2]] 

    return perm_s

print make_perm([-2,-1,1,2])

输出:

[[-2, -1], [-2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2], [2, -1], [2, 1]]

此解决方案处理不同的项目长度

def perm(list_to_perm,perm_l,items):
    if len(perm_l) == items:
        print perm_l
    else:
        for i in  list_to_perm:

            if i not in perm_l:
                if -i not in perm_l:
                    perm(list_to_perm,list(perm_l) +[i],items)


a = [-2,-1,1,2]
perm(a,[],2)

输出:

[-2, -1]
[-2, 1]
[-1, -2]
[-1, 2]
[1, -2]
[1, 2]
[2, -1]
[2, 1]

这看起来有点奇怪。 我还在学习python。 我正在复制代码,所以顺序更自然。 可能有捷径。 事实证明这是Rosalind.info问题的答案。 我不喜欢这些代码,它有点吵,但它有效。

def signedPerm(x):
        if len(x) == 1:
            yield x
            x[0]*=-1
            yield x
        else:
            for i in range(len(x)):
            for s in [1, -1]:
            y=[x[i]*s]
            for j in signedPerm(x[:i]+x[i+1:]):
              yield y+j

然后打电话

[x for x in signedPerm(list(set([abs(y) for y in [-1, -2, 1, 4]])))]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM