In [1]:
import Data.List
In [2]:
permutationsWithoutDups :: String -> [String]
permutationsWithoutDups [] = [""]
permutationsWithoutDups [x] = [ [x] ]
permutationsWithoutDups (x:xs) =
let
wrap char left right = intercalate [char] [left, right]
interweave char permutation = zipWith (wrap char) (inits permutation) (tails permutation)
in
concatMap (interweave x) $ permutationsWithoutDups xs
In [3]:
permutationsWithoutDups "abc"
In [4]:
permutations "abc"
In [5]:
import Test.QuickCheck
Test against the reference implementation:
In [6]:
testPermutations :: String -> Bool
testPermutations s =
sort (permutations s) == sort (permutationsWithoutDups s)
In [7]:
quickCheckWith stdArgs { maxSize = 10 } testPermutations
Test problem invariants:
In [8]:
import Data.Set
In [9]:
testPermutationsInvariants :: String -> Bool
testPermutationsInvariants s =
let
resultList = permutationsWithoutDups s
resultSet = Data.Set.fromList resultList
expectedLength = length resultList == product [1..length s]
expectedChars = all (\x -> sort x == sort s) resultList
-- noDuplicates = length resultList == length resultSet
in
expectedChars && expectedLength -- && noDuplicates
In [10]:
quickCheckWith stdArgs { maxSize = 10 } testPermutationsInvariants
We need to write a custom string generator that generates strings of unique characters as defined in problem description, otherwise the test for the noDuplicates invariant will fail.