使用重复元素生成列表的排列

Jos*_*shD 19 python permutation

在Python中,使用itertools模块生成列表的所有排列非常简单.我有一种情况,我使用的列表只有两个字符(即'1122').我想生成所有独特的排列.

对于字符串'1122',有6个唯一的排列(1122,1212,1221等),但itertools.permutations将产生24个项目.仅记录唯一排列很简单,但是由于考虑了所有720个项目,因此收集它们所需的时间要长得多.

是否有一个函数或模块在生成排列时会考虑重复的元素,所以我不必自己编写?

hug*_*own 18

这个网页看起来很有前景.

def next_permutation(seq, pred=cmp):
    """Like C++ std::next_permutation() but implemented as
    generator. Yields copies of seq."""
    def reverse(seq, start, end):
        # seq = seq[:start] + reversed(seq[start:end]) + \
        #       seq[end:]
        end -= 1
        if end <= start:
            return
        while True:
            seq[start], seq[end] = seq[end], seq[start]
            if start == end or start+1 == end:
                return
            start += 1
            end -= 1
    if not seq:
        raise StopIteration
    try:
        seq[0]
    except TypeError:
        raise TypeError("seq must allow random access.")
    first = 0
    last = len(seq)
    seq = seq[:]
    # Yield input sequence as the STL version is often
    # used inside do {} while.
    yield seq[:]
    if last == 1:
        raise StopIteration
    while True:
        next = last - 1
        while True:
            # Step 1.
            next1 = next
            next -= 1
            if pred(seq[next], seq[next1]) < 0:
                # Step 2.
                mid = last - 1
                while not (pred(seq[next], seq[mid]) < 0):
                    mid -= 1
                seq[next], seq[mid] = seq[mid], seq[next]
                # Step 3.
                reverse(seq, next1, last)
                # Change to yield references to get rid of
                # (at worst) |seq|! copy operations.
                yield seq[:]
                break
            if next == first:
                raise StopIteration
    raise StopIteration

>>> for p in next_permutation([int(c) for c in "111222"]):
...     print p
... 
[1, 1, 1, 2, 2, 2]
[1, 1, 2, 1, 2, 2]
[1, 1, 2, 2, 1, 2]
[1, 1, 2, 2, 2, 1]
[1, 2, 1, 1, 2, 2]
[1, 2, 1, 2, 1, 2]
[1, 2, 1, 2, 2, 1]
[1, 2, 2, 1, 1, 2]
[1, 2, 2, 1, 2, 1]
[1, 2, 2, 2, 1, 1]
[2, 1, 1, 1, 2, 2]
[2, 1, 1, 2, 1, 2]
[2, 1, 1, 2, 2, 1]
[2, 1, 2, 1, 1, 2]
[2, 1, 2, 1, 2, 1]
[2, 1, 2, 2, 1, 1]
[2, 2, 1, 1, 1, 2]
[2, 2, 1, 1, 2, 1]
[2, 2, 1, 2, 1, 1]
[2, 2, 2, 1, 1, 1]
>>> 
Run Code Online (Sandbox Code Playgroud)

2017年8月12日

七年后,这是一个更好的算法(更好的清晰度):

from itertools import permutations

def unique_perms(series):
    return {"".join(p) for p in permutations(series)}

print(sorted(unique_perms('1122')))
Run Code Online (Sandbox Code Playgroud)


Mar*_*ese 9

更多 Itertools有一个功能:

more-itertools.distinct_permutations(iterable)

产生iterable 中元素的连续不同排列。

等价于set(permutations(iterable)),但不会生成和丢弃重复项。对于更大的输入序列,这更有效

from more_itertools import distinct_permutations

for p in distinct_permutations('1122'):
    print(''.join(p))

# 2211
# 2121
# 1221
# 2112
# 1212
# 1122
Run Code Online (Sandbox Code Playgroud)

安装:

pip install more-itertools
Run Code Online (Sandbox Code Playgroud)

  • 无疑是最简洁的答案 (2认同)