This is my solution for CodeEval challenge 44.
You are writing out a list of numbers.Your list contains all numbers with exactly Di digits in its decimal representation which are equal to i, for each i between 1 and 9, inclusive. You are writing them out in ascending order. For example, you might be writing every number with two '1's and one '5'. Your list would begin 115, 151, 511, 1015, 1051. Given N, the last number you wrote, compute what the next number in the list will be. The number of 1s, 2s, ..., 9s is fixed but the number of 0s is arbitrary.
Your program should accept as its first argument a path to a filename. Each line in this file is one test case. Each test case will contain an integer n < 10^6. E.g.
115 842 8000
For each line of input, generate a line of output which is the next integer in the list. E.g.
151 2048 80000
followingInteger takes a number in its decimal representation and returns the next higher permutation of the digits of the number. If there isn't a larger permutation of the digits, a '0' may be added to the digits:
ghci> followingInteger "123" "132" ghci> followingInteger "10" "100"
The entire program can be used like this:
where ch044_input is a file containing one integer on each line.
import Data.List (partition, sort) import System.Environment (getArgs) followingInteger :: String -> String followingInteger digits | isSortedDesc digits = lowestPermutation ('0' : digits) | otherwise = nextHigherPermutation digits isSortedDesc :: (Ord a) => [a] -> Bool isSortedDesc xs = all (uncurry (>=)) $ zip xs (tail xs) lowestPermutation :: String -> String lowestPermutation digits = let (zeros, nonZeros) = partition (== '0') digits (lowestNonZeroDigit:otherDigits) = sort nonZeros in lowestNonZeroDigit : zeros ++ otherDigits nextHigherPermutation :: String -> String nextHigherPermutation = snd . foldr foldFun (False, "") where foldFun d (True, digits) = (True, d:digits) foldFun d (False, digits) | null biggerDigits = (False, d:digits) | otherwise = (True, newTail) where (biggerDigits, smallerDigits) = partition (> d) digits (swapDigit:otherDigits) = sort biggerDigits newTail = swapDigit : sort smallerDigits ++ (d : otherDigits) mapFileLines :: (String -> String) -> IO () mapFileLines f = do (fileName:_) <- getArgs contents <- readFile fileName mapM_ (putStrLn . f) $ lines contents main = mapFileLines followingInteger
I'm pretty new to Haskell, so please criticize my code in every way possible!
I'm especially interested in ways to make the code more readable!