web-dev-qa-db-ja.com

pythonで指定された文字列の可能なすべての順列を見つける

文字列があります。文字列内の文字の順序を変更して、その文字列からすべての順列を生成したいと思います。たとえば、次のように言います。

x='stack'

私が欲しいのはこのようなリストです

l=['stack','satck','sackt'.......]

現在、私は文字列のリストキャストを繰り返し、2文字をランダムに選択し、それらを転置して新しい文字列を形成し、それをセットキャストのlに追加しています。文字列の長さに基づいて、可能な置換の数を計算し、設定サイズが制限に達するまで反復を続けています。これを行うにはより良い方法が必要です。

71
Nihar Sarangi

Itertoolsモジュールには、permutations()という便利なメソッドがあります。 ドキュメント 言います:

itertools.permutations(iterable [、r])

Iterableの要素の連続したr長の順列を返します。

Rが指定されていないかNoneの場合、rはデフォルトで反復可能の長さになり、すべての可能な完全長の順列が生成されます。

順列は辞書式のソート順で発行されます。そのため、入力iterableがソートされている場合、並べ替えタプルはソートされた順序で生成されます。

ただし、並べ替えられた文字を文字列として結合する必要があります。

>>> from itertools import permutations
>>> perms = [''.join(p) for p in permutations('stack')]
>>> perms

['stack'、 'stakc'、 'stcak'、 'stcka'、 'stkac'、 'stkca'、 'satck'、 'satkc'、 'sactk'、 'sackt'、 'saktc'、 'sakct'、 ' sctak」、「sctka」、「scatk」、「scakt」、「sckta」、「sckat」、「sktac」、「sktca」、「skatc」、「skact」、「skcta」、「skcat」、「tsack」 、「tsakc」、「tscak」、「tscka」、「tskac」、「tskca」、「tasck」、「taskc」、「tacsk」、「tacks」、「taksc」、「takcs」、「tcsak」、「 tcska」、「tcask」、「tcaks」、「tcksa」、「tckas」、「tksac」、「tksca」、「tkasc」、「tkacs」、「tkcsa」、「tkcas」、「astck」、「astkc」 、「asctk」、「asckt」、「asktc」、「askct」、「atsck」、「atskc」、「atcsk」、「atcks」、「atksc」、「atkcs」、「acstk」、「acskt」、「 Actsk 、「csakt」、「cskta」、「cskat」、「ctsak」、「ctska」、「ctask」、「ctaks」、「ctksa」、「ctkas」、「castk」、「caskt」、「catsk」、「 catks」、「cakst」、「cakts」、「cksta」、「cksat」、「cktsa」、「cktas」、「ckast」、「ckats」​​、「kstac」、「kstca」、「ksatc」、「ksact」 、「kscta」、「kscat」、「ktsac」、「ktsca」、「ktasc」、「ktacs」、「ktcsa」、「ktcas」、「kastc」、「kasct」、「katsc」、 「katcs」、「kacst」、「kacts」、「kcsta」、「kcsat」、「kctsa」、「kctas」、「kcast」、「kcats」]

重複に悩まされている場合は、setのような重複のない構造にデータを適合させてください。

>>> perms = [''.join(p) for p in permutations('stacks')]
>>> len(perms)
720
>>> len(set(perms))
360

これは従来型キャストと考えられていたものではなく、set()コンストラクターの呼び出しであると指摘してくれた@pstに感謝します。

117

すべてのNを取得できます!多くのコードなしの順列

def permutations(string, step = 0):

    # if we've gotten to the end, print the permutation
    if step == len(string):
        print "".join(string)

    # everything to the right of step has not been swapped yet
    for i in range(step, len(string)):

        # copy the string (store as array)
        string_copy = [character for character in string]

        # swap the current index with the step
        string_copy[step], string_copy[i] = string_copy[i], string_copy[step]

        # recurse on the portion of the string that has not been swapped yet (now it's index will begin with step + 1)
        permutations(string_copy, step + 1)
32
illerucis

最小限のコードで文字列の置換を行う別の方法を次に示します。基本的にループを作成してから、一度に2文字をスワップし続けます。ループ内で再帰が行われます。インデクサーが文字列の長さに達したときにのみ印刷します。例:開始点のABC iとループの再帰パラメーターj

ここに、左から右、上から下への動作の視覚的なヘルプがあります(順列の順序です)

enter image description here

コード :

def permute(data, i, length): 
    if i==length: 
        print(''.join(data) )
    else: 
        for j in range(i,length): 
            #swap
            data[i], data[j] = data[j], data[i] 
            permute(data, i+1, length) 
            data[i], data[j] = data[j], data[i]  


string = "ABC"
n = len(string) 
data = list(string) 
permute(data, 0, n)
7
grepit

スタックオーバーフローユーザーは既にいくつかの強力なソリューションを投稿していますが、さらに別のソリューションを示したいと思いました。これはもっと直感的だと思う

アイデアは、特定の文字列に対して:アルゴリズム(擬似コード)によって再帰できるということです。

順列=文字+文字列内の文字の順列(文字列-文字)

それが誰かを助けることを願っています!

def permutations(string):
    """Create all permutations of a string with non-repeating characters
    """
    permutation_list = []
    if len(string) == 1:
        return [string]
    else:
        for char in string:
            [permutation_list.append(char + a) for a in permutations(string.replace(char, ""))]
    return permutation_list
6
BushMinusZero

@Adrianoと@illerucisが投稿したものとは別のアプローチを次に示します。これによりランタイムが向上し、時間を測定することで自分で確認できます。

def removeCharFromStr(str, index):
    endIndex = index if index == len(str) else index + 1
    return str[:index] + str[endIndex:]

# 'ab' -> a + 'b', b + 'a'
# 'abc' ->  a + bc, b + ac, c + ab
#           a + cb, b + ca, c + ba
def perm(str):
    if len(str) <= 1:
        return {str}
    permSet = set()
    for i, c in enumerate(str):
        newStr = removeCharFromStr(str, i)
        retSet = perm(newStr)
        for elem in retSet:
            permSet.add(c + elem)
    return permSet

任意の文字列「dadffddxcf」の場合、順列ライブラリでは1.1336秒、この実装では9.125秒、@ Adrianoおよび@illerucisバージョンでは16.357秒かかりました。もちろん、それでも最適化できます。

5
Rooky

一意の順列を返す簡単な関数を次に示します。

def permutations(string):
    if len(string) == 1:
        return string

    recursive_perms = []
    for c in string:
        for perm in permutations(string.replace(c,'',1)):
            revursive_perms.append(c+perm)

    return set(revursive_perms)
5
ArashkG

なぜあなたは簡単ではないのですか:

from itertools import permutations
perms = [''.join(p) for p in permutations(['s','t','a','c','k'])]
print perms
print len(perms)
print len(set(perms))

あなたが見ることができるようにあなたは重複を得ません:

 ['stack', 'stakc', 'stcak', 'stcka', 'stkac', 'stkca', 'satck', 'satkc', 
'sactk', 'sackt', 'saktc', 'sakct', 'sctak', 'sctka', 'scatk', 'scakt', 'sckta',
 'sckat', 'sktac', 'sktca', 'skatc', 'skact', 'skcta', 'skcat', 'tsack', 
'tsakc', 'tscak', 'tscka', 'tskac', 'tskca', 'tasck', 'taskc', 'tacsk', 'tacks', 
'taksc', 'takcs', 'tcsak', 'tcska', 'tcask', 'tcaks', 'tcksa', 'tckas', 'tksac', 
'tksca', 'tkasc', 'tkacs', 'tkcsa', 'tkcas', 'astck', 'astkc', 'asctk', 'asckt', 
'asktc', 'askct', 'atsck', 'atskc', 'atcsk', 'atcks', 'atksc', 'atkcs', 'acstk', 
'acskt', 'actsk', 'actks', 'ackst', 'ackts', 'akstc', 'aksct', 'aktsc', 'aktcs', 
'akcst', 'akcts', 'cstak', 'cstka', 'csatk', 'csakt', 'cskta', 'cskat', 'ctsak', 
'ctska', 'ctask', 'ctaks', 'ctksa', 'ctkas', 'castk', 'caskt', 'catsk', 'catks', 
'cakst', 'cakts', 'cksta', 'cksat', 'cktsa', 'cktas', 'ckast', 'ckats', 'kstac', 
'kstca', 'ksatc', 'ksact', 'kscta', 'kscat', 'ktsac', 'ktsca', 'ktasc', 'ktacs', 
'ktcsa', 'ktcas', 'kastc', 'kasct', 'katsc', 'katcs', 'kacst', 'kacts', 'kcsta', 
'kcsat', 'kctsa', 'kctas', 'kcast', 'kcats']
    120
    120
    [Finished in 0.3s]
2
Vincenzo

以下は、itertoolsを使用せずに、文字列sのすべての順列のリストを個別の文字(必ずしも辞書式ソート順である必要はない)で返すための illerucis のコードのわずかに改善されたバージョンです。

def get_perms(s, i=0):
    """
    Returns a list of all (len(s) - i)! permutations t of s where t[:i] = s[:i].
    """
    # To avoid memory allocations for intermediate strings, use a list of chars.
    if isinstance(s, str):
        s = list(s)

    # Base Case: 0! = 1! = 1.
    # Store the only permutation as an immutable string, not a mutable list.
    if i >= len(s) - 1:
        return ["".join(s)]

    # Inductive Step: (len(s) - i)! = (len(s) - i) * (len(s) - i - 1)!
    # Swap in each suffix character to be at the beginning of the suffix.
    perms = get_perms(s, i + 1)
    for j in range(i + 1, len(s)):
        s[i], s[j] = s[j], s[i]
        perms.extend(get_perms(s, i + 1))
        s[i], s[j] = s[j], s[i]
    return perms
1
Adriano
def permute(seq):
    if not seq:
        yield seq
    else:
        for i in range(len(seq)):
            rest = seq[:i]+seq[i+1:]
            for x in permute(rest):
                yield seq[i:i+1]+x

print(list(permute('stack')))
1
Srivastava

itertools.combinations または itertools.permutations を参照してください。

1
Brian Cain

順列を使用した簡単なソリューション。

from itertools import permutations

def stringPermutate(s1):
    length=len(s1)
    if length < 2:
        return s1

    perm = [''.join(p) for p in permutations(s1)]

    return set(perm)
0
Nelson Guest

本当にシンプルなジェネレーターバージョンを次に示します。

def find_all_permutations(s, curr=[]):
    if len(s) == 0:
        yield curr
    else:
        for i, c in enumerate(s):
            for combo in find_all_permutations(s[:i]+s[i+1:], curr + [c]):
                yield "".join(combo)

それほど悪くないと思います!

0
Gritty Kitty
from itertools import permutations
perms = [''.join(p) for p in permutations('ABC')]

perms = [''.join(p) for p in permutations('stack')]
0
Satish Kumar
def permute_all_chars(list, begin, end):

    if (begin == end):
        print(list)
        return

    for current_position in range(begin, end + 1):
        list[begin], list[current_position] = list[current_position], list[begin]
        permute_all_chars(list, begin + 1, end)
        list[begin], list[current_position] = list[current_position], list[begin]


given_str = 'ABC'
list = []
for char in given_str:
    list.append(char)
permute_all_chars(list, 0, len(list) -1)
def perm(string):
   res=[]
   for j in range(0,len(string)):
       if(len(string)>1):
           for i in perm(string[1:]):
               res.append(string[0]+i)
       else:
           return [string];
       string=string[1:]+string[0];
   return res;
l=set(perm("abcde"))

これは、再帰を使用して順列を生成する1つの方法です。入力として文字列「a」、「ab」、「abc」を使用することで、コードを簡単に理解できます。

すべてNを取得します!これとの順列、重複なし。

0
Jasser
def f(s):
  if len(s) == 2:
    X = [s, (s[1] + s[0])]
      return X
else:
    list1 = []
    for i in range(0, len(s)):
        Y = f(s[0:i] + s[i+1: len(s)])
        for j in Y:
            list1.append(s[i] + j)
    return list1
s = raw_input()
z = f(s)
print z
0

このプログラムは重複を排除しませんが、最も効率的なアプローチの1つだと思います。

s=raw_input("Enter a string: ")
print "Permutations :\n",s
size=len(s)
lis=list(range(0,size))
while(True):
    k=-1
    while(k>-size and lis[k-1]>lis[k]):
        k-=1
    if k>-size:
        p=sorted(lis[k-1:])
        e=p[p.index(lis[k-1])+1]
        lis.insert(k-1,'A')
        lis.remove(e)
        lis[lis.index('A')]=e
        lis[k:]=sorted(lis[k:])
        list2=[]
        for k in lis:
                list2.append(s[k])
        print "".join(list2)
    else:
                break
0

誰もが自分のコードの匂いが大好きです。私が見つけたものを共有するだけです:

def get_permutations(Word):
    if len(Word) == 1:
        yield Word

    for i, letter in enumerate(Word):
        for perm in get_permutations(Word[:i] + Word[i+1:]):
            yield letter + perm
0
r_2

さらに別のイニシアチブと再帰的ソリューション。アイデアは、ピボットとして文字を選択してから、Wordを作成することです。

# for a string with length n, there is a factorial n! permutations
alphabet = 'abc'
starting_perm = ''
# with recursion
def premuate(perm, alphabet):
    if not alphabet: # we created one Word by using all letters in the alphabet
        print(perm + alphabet)
    else:
        for i in range(len(alphabet)): # iterate over all letters in the alphabet
            premuate(perm + alphabet[i], alphabet[0:i] + alphabet[i+1:]) # chose one letter from the alphabet

# call it            
premuate(starting_perm, alphabet)

出力:

abc
acb
bac
bca
cab
cba
0
Faroq AL-Tam