Functional programming provides such an elegant system for processing data. I’m going to stop right there before I start fanboying. Haskell deals with the impurity of I/O by providing monads, which is further simplified through the interact
function, which takes a function that takes a string and returns a string. The input string comes from stdin and the output string comes from stdout.
interact :: (String -> String) -> IO ()
That’s all well and good for simple input, like a CSV file, but when you have some complicated sequences of meaningful input, how do you manage?
Enter the Google Code Jam problems. These are simple (or not-so-simple) algorithmic challenges perfectly suited to functionl programming… except for the input and output. I will be using this blog post to demonstrate the use of the interact
function on different input cases for Google Code Jam problems. When reading the code explanations, read the comments from the bottom of the function to the top; it’s easier to see how the input string is processed that way.
2010 - Round 1B - A. File Fix-it
Input
3
0 2
/home/gcj/finals
/home/gcj/quals
2 1
/chicken
/chicken/egg
/chicken
1 3
/a
/a/b
/a/c
/b/b
Output
Case #1: 4
Case #2: 0
Case #3: 4
Solution Signature & Main
diffDirectories :: ([String],[String]) -> Int
main = interact $ unlines .
-- we need a method of attaching the case number to each result
zipWith (++) ["Case #" ++ show i ++ ": " | i <- [1..]] .
-- we can now execute the solver `diffDirectories` on the pairs of directories
map ((show . diffDirectories) .
-- we split the test case directories into the existing and new directories
(\a -> splitAt (read (head (words (head a)))) (tail a))) .
-- we need to seperate each test case to processes them individually
groupBy (\_ b -> head b == '/') .
-- we don't care much for the first line; we can calulate the number of cases
tail . lines
2014 - Round 1B - A. The Repeater
Input
5
2
mmaw
maw
2
gcj
cj
3
aaabbb
ab
aabb
2
abc
abc
3
aabc
abbc
abcc
Output
Case #1: 1
Case #2: Fegla Won
Case #3: 4
Case #4: 0
Case #5: 3
Solution Signature & Main
solution :: [String] -> Maybe Int
main = interact $ unlines .
zipWith (++) ["Case #" ++ show i ++ ": " | i <- [1..]] .
-- the solver will return Nothing if Fegla won
-- otherwise the result can just be displayed
map ((maybe "Fegla Won" show . solution) . tail) .
-- group together all strings for each test case
groupBy (\_ b -> head b `elem` ['a'..'z']) . tail . lines
Keep an eye on this post for potential updated test cases.