You should usually not put the import
s into your functions. While Python does not re-import a module it has already imported, it still needs to run the check for this. So this introduces an unnecessary overhead, when running the function multiple times. There are a few use cases for doing this, though, like not wanting to pollute the global namespace if that module does some dirty hacks during its initialization or it takes a very long time to import and you only want to do this sometimes (and only run the function once). But random
is no such module.
Your code makes this also too complicated. The biggest part of your algorithm is making sure that you don't re-use a letter you already used. You can use random.sample
for this, instead. It randomly samples (duh) from a sequence (anything iterable and indexable) without replacement:
import random
def anagram(value):
'''Returns random anagram of given value'''
return ''.join(random.sample(value, len(value)))
An alternative would be random.shuffle
, which shuffles a list in place, but this has the overhead of casting to a list first. The documentation actually recommends using the first one (which is also a lot clearer IMO).
def anagram(value):
'''Returns random anagram of given value'''
value_list = list(value)
random.shuffle(value_list)
return ''.join(value_list)
As for corner cases to test? The obvious one is the empty string ''
. Then maybe a string containing only one distinct letter, like 'aaa'
(to catch some very weird algorithm that only looks at the set of letters, which would be quite wrong, of course). And then finally maybe the scaling behavior of the algorithm so strings of increasing length.
All should be tested for example with this:
from collections import Counter
def test_anagram_function(s):
assert Counter(s) == Counter(anagram(s))