如何生成排列而不生成重复结果但具有固定数量的字符Python

时间:2016-07-23 17:13:15

标签: python algorithm permutation itertools

我试图想出一种方法来生成一个字符串的所有排列,这个字符串有几个重复的字符,但不会生成重复的元组。

现在我正在使用itertools.permutations()。它有效,但我需要删除重复,不能使用set()来删除重复。

我期待什么样的结果?好吧,例如,我希望获得DDRR的所有组合,itertools.permutations()的内容是我会DDRR大约四次,因为itertools看到了D R就好像它们不同,与list(itertools.permutations('DDRR')) s相同。

[('D', 'D', 'R', 'R'), ('D', 'D', 'R', 'R'), ('D', 'R', 'D', 'R'), ('D', 'R', 'R', 'D'), ('D', 'R', 'D', 'R'), ('D', 'R', 'R', 'D'), ('D', 'D', 'R', 'R'), ('D', 'D', 'R', 'R'), ('D', 'R', 'D', 'R'), ('D', 'R', 'R', 'D'), ('D', 'R', 'D', 'R'), ('D', 'R', 'R', 'D'), ('R', 'D', 'D', 'R'), ('R', 'D', 'R', 'D'), ('R', 'D', 'D', 'R'), ('R', 'D', 'R', 'D'), ('R', 'R', 'D', 'D'), ('R', 'R', 'D', 'D'), ('R', 'D', 'D', 'R'), ('R', 'D', 'R', 'D'), ('R', 'D', 'D', 'R'), ('R', 'D', 'R', 'D'), ('R', 'R', 'D', 'D'), ('R', 'R', 'D', 'D')] 我得到:

[('D', 'R', 'R', 'D'), ('R', 'D', 'R', 'D'), ('R', 'R', 'D', 'D'), ('D', 'R', 'D', 'R'), ('D', 'D', 'R', 'R'), ('R', 'D', 'D', 'R')]

我想要的理想结果是:

#!/usr/bin/perl

$f = '2.txt';
open (F,"<$f") or die "Can not open\n";
my %hash;
while (<F>) {
    chomp $_;
    @data = split (/\|/,$_);
    foreach $data (@data) {
        if ($data ~= /^52=(.*)/) {
            $hash{$1}++;
        }
    }
}
for my $j (keys %hash) {
    print "$j: ", $hash{j}, "\n";
}

3 个答案:

答案 0 :(得分:1)

如果您的字符串包含大量重复字符,那么您可以使用基于组合的算法来生成排列。

基本上,这是通过选择一个字母并查找该字母的副本可以去的所有地方来实现的。通过这些可能性,您可以找到下一个字母所在的所有位置,依此类推。

代码:

from collections import Counter
from itertools import combinations

def perms_without_reps(s):
    partitions = list(Counter(s).items())
    k = len(partitions)
    def _helper(idxset, i):
        if len(idxset) == 0:
            yield ()
            return
        for pos in combinations(idxset, partitions[i][1]):
            for res in _helper(idxset - set(pos), i+1):
                yield (pos,) + res

    n = len(s)
    for poses in _helper(set(range(n)), 0):
        out = [None] * n
        for i, pos in enumerate(poses):
            for idx in pos:
                out[idx] = partitions[i][0]
        yield out

像这样运行:

for p in perms_without_reps('DDRR'):
    print p

两个重要的注释:

  • 这不会生成以任何特定方式排序的输出。如果您想要排序输出,请在permutations.sort()之前添加k =,将_helper(idxset - set(pos), i+1)替换为_helper(sorted(set(idxset) - set(pos)), i+1),并将_helper(set(range(n)), 0)替换为_helper(list(range(n)), 0)。这会使功能稍慢。
  • 如果您的重复次数很大且不平衡,则此功能非常有效。例如,任何基于排列的方法都将永远用于输入'A'*100 + 'B'*2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABB),而这种方法几乎可以立即完成5151个唯一排列。

答案 1 :(得分:0)

这将是创建具有重复元素的集合的排列的标准方法:计算每个元素的出现次数(使用例如关联数组或字典),循环遍历字典中的元素并且每次附加元素对于排列,并与字典的其余部分一起递归。但是,对于很长的输入数组,它永远不会很快;但是没有什么可能的。

(JavaScript中的代码示例;我不会说Python;翻译应该很容易。)

function permute(set) {
    var alphabet = {};
    for (var s in set) {
        if (!alphabet[set[s]]) alphabet[set[s]] = 1;
        else ++alphabet[set[s]];
    }                               // alphabet = {'a':5, 'b':2, 'r':2, 'c':1, 'd':1}
    perm("", set.length);

    function perm(part, level) {
        for (var a in alphabet) {   // every letter in alphabet
            if (alphabet[a]) {      // one or more of this letter available
                --alphabet[a];      // decrement letter count
                if (level > 1) perm(part + a, level - 1);  // recurse with rest
                else document.write(part + a + "<br>");    // deepest recursion level
                ++alphabet[a];      // restore letter count
            }
        }
    }
}
permute(['a','b','r','a','c','a','d','a','b','r','a']); // 83,160 unique permutations
                                                        // instead of 39,916,800 non-
                                                        // unique ones plus filtering

答案 2 :(得分:0)

通常每个排列算法都会生成n!/(n-r)!个结果,但您可以决定实施一个检查重复的算法,这个算法应该很有趣。

让我们看看这是否有帮助。

def __permutate(self, objectToPermute):
    in_list = []

    for i in range(self.__cur, len(objectToPermute)):
        in_list.append(self.__swap(self.__cur, i, objectToPermute))

    ''' At initial call, self.__cur = 0
       and self.__permSize would be the r in the permutation formula '''
    if self.__cur < self.__permSize - 1:
        self.__cur += 1

        for obj in in_list:
            self.__permutate(obj)

        self.__cur -= 1


    if self.__cur == self.__permSize -1:
        for obj in in_list:
            #this does the job
            if self.norepeat and obj in self.__perm_obj:
                continue
            self.__perm_obj.append(obj[:self.__permSize])

你一定注意到了,我把它从很久以前写过的课程中拉出来了,它是一种我想称为Melon算法的Permutation算法(不要小心)。

代码的这一部分只是递归地置换一个对象,使用交换函数,因为它存在于类中但你可以很容易地编写出来......现在到主要的要点,为了避免重复所有你要做的是确保将跳过attrib self.norepeat = True和每个重复的对象。如果您需要完整的课程,我很乐意分享

我需要反馈,以便知道你是否得到我所说的