Reputation: 10961
I was thinking about this problem today, and I came with the following pseudocode (Python 3.2) :
def anagrams( string ):
for c in string:
anagram = c + anagram( string - {c} ) # remove the char from its position in the string
print(anagram)
return
def main():
word = "abcd"
anagrams( word )
return
However, I'd like to know a pythonic way to do this operation: anagram = c + anagram( string - {c} )
How could I remove that char from the string? so for example:
"abc" -> 'a' + "bc" -> 'a' + 'b' + "c" -> 'a' + 'b' + 'c' = 'abc'
+ "cb" -> 'a' + 'c' + "b" -> 'a' + 'c' + 'b' = 'acb'
-> 'b' + "ac" -> 'b' + 'a' + "c" -> 'b' + 'a' + 'c' = 'bac'
+ "ca" -> 'b' + 'c' + "a" -> 'b' + 'c' + 'a' = 'bca'
-> 'c' + "ba" -> 'c' + 'b' + "a" -> 'c' + 'b' + 'a' = 'cba'
+ "ab" -> 'c' + 'a' + "b" -> 'c' + 'a' + 'b' = 'cab'
Thanks
Upvotes: 14
Views: 39265
Reputation: 72001
Here's some of the suggestions wrapped up to make a new script, called anagram
$ anagram hit
hit
hti
iht
ith
thi
tih
#!/usr/bin/env python3
import argparse
import itertools
import sys
parser = argparse.ArgumentParser()
parser.add_argument("word", help="A word to generate anagrams for.")
args = parser.parse_args()
perms = [''.join(perm) for perm in itertools.permutations(args.word)]
for perm in perms:
print(perm)
Upvotes: 0
Reputation: 778
Just to note, @sloth's answer gives a slightly unexpected result if the string contains more than one instance of a letter - duplicate permutations:
["".join(perm) for perm in itertools.permutations('aabc')]
Results in:
['aabc',
'aacb',
'abac',
'abca',
'acab',
'acba',
'aabc',
'aacb',
'abac',
'abca',
'acab',
'acba',
'baac',
'baca',
'baac',
'baca',
'bcaa',
'bcaa',
'caab',
'caba',
'caab',
'caba',
'cbaa',
'cbaa']
If this isn't the desired result, using 'set' will eliminate the dups. Although if you want a list, you'll need to relist (also 'set' doesn't maintain order so use 'sorted'):
sorted(set(["".join(perm) for perm in itertools.permutations("aabc")]))
Results in:
['aabc',
'aacb',
'abac',
'abca',
'acab',
'acba',
'baac',
'baca',
'bcaa',
'caab',
'caba',
'cbaa']
Upvotes: 5
Reputation: 101072
Why not just use itertools?
>>> import itertools
>>> ["".join(perm) for perm in itertools.permutations("abc")]
['abc', 'acb', 'bac', 'bca', 'cab', 'cba']
The documentation also contains code how the permutation is done.
Edit:
def all_perms(elements):
if len(elements) <=1:
yield elements
else:
for perm in all_perms(elements[1:]):
for i in range(len(elements)):
yield perm[:i] + elements[0:1] + perm[i:]
word = "abc"
print list(all_perms(word))
Without itertools
and without generators
:
def all_perms(elements):
if len(elements) <=1:
return elements
else:
tmp = []
for perm in all_perms(elements[1:]):
for i in range(len(elements)):
tmp.append(perm[:i] + elements[0:1] + perm[i:])
return tmp
Result:
['abc', 'bac', 'bca', 'acb', 'cab', 'cba']
Upvotes: 34
Reputation: 9721
Use the itertools
module.
import itertools
perms = [''.join(perm) for perm in itertools.permutations('abc')]
Upvotes: 6
Reputation: 8937
You can cast the word to a list, run remove and then use join to get it back together again.
word = 'abca'
letters = list(word)
letters.remove('a') # Only deletes the first 'a'
word = ''.join(letters)
Upvotes: 0