-
Notifications
You must be signed in to change notification settings - Fork 0
/
work-hours-statistics.hs
63 lines (53 loc) · 2.2 KB
/
work-hours-statistics.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
-- Work hours statistics
-- Each event's title must only consist of a sequnece of letters; one letter per worker.
-- No spaces are allowed. For example, "js" if Jakob and Simon worked at that time.
-- input: output of ical2text
-- usage: ical2text < cal.ics | work-hours-statistics
import Control.Monad
import System.IO
import System.Exit
import qualified Data.Char as C
import Data.List as L
import Data.Map as M
import Data.Maybe
import qualified Data.Text as T
import Text.Read
import Text.Printf
type ResultMap = M.Map Char Float
main :: IO ()
main = do
input <- fmap lines getContents
result <- foldM processLine empty input
printResult result
processLine :: ResultMap -> String -> IO ResultMap
processLine map line = do
let start:_:hoursField:rest = words line
let keysField = takeWhile (/='@') $ unwords rest
let keys = T.unpack . T.map C.toUpper . T.strip . T.pack $ keysField :: String
let hours = maybeRead hoursField
when (L.null keys) $
printError $ "warning: no letters given at event " ++ start
when (L.length keys > 6) $
printError $ "warning: more than 6 letters of names at event " ++ start
when (L.length keys /= (L.length . L.nub) keys) $
die $ "error: duplicate letters in " ++ keys ++ " at event " ++ start
when (isNothing hours) $
die $ "error: invalid hours value in 3rd column. number expected but saw " ++ hoursField ++ " at event " ++ start
foldM (updateResultMap $ fromJust hours) map keys
updateResultMap :: Float -> ResultMap -> Char -> IO ResultMap
updateResultMap hours map key = return $ M.alter (addHours hours) key map
addHours :: Float -> Maybe Float -> Maybe Float
addHours hoursToAdd maybeHours = Just $ maybe hoursToAdd (+hoursToAdd) maybeHours
printResult :: ResultMap -> IO ()
printResult m = do
putStrLn $ "Arbeitsstunden insgesamt: " ++ show total
let stat = M.toAscList m
mapM_ printStatLine stat
where
printStatLine :: (Char, Float) -> IO ()
printStatLine (n, h) = putStrLn $ printf "%c: %.2f h (%.2f %%)" n h (h / total * 100)
total :: Float
total = M.foldl (+) 0 m
maybeRead = fmap fst . listToMaybe . reads
printError :: String -> IO ()
printError = hPutStrLn stderr