forked from steger/pr3-sose2026
implemented the statistics exercise
parent
5dff437064
commit
9b5014ce01
|
|
@ -1,17 +1,63 @@
|
||||||
import Data.List (nub, sortOn)
|
import Data.Function (on)
|
||||||
|
import Data.List (groupBy, nub, sortOn)
|
||||||
import System.IO
|
import System.IO
|
||||||
|
|
||||||
-- separator -> Input -> Separated Input
|
-- separator -> Input -> Separated Input
|
||||||
-- split :: Char -> String -> [String]
|
split :: Char -> String -> [String]
|
||||||
|
split _ "" = []
|
||||||
|
split sep str =
|
||||||
|
let (word, rest) = break (== sep) str
|
||||||
|
in word : case rest of
|
||||||
|
[] -> []
|
||||||
|
(_ : xs) -> split sep xs
|
||||||
|
|
||||||
-- data Entry =
|
-- Data structure for a student entry
|
||||||
|
data Entry = Entry
|
||||||
|
{ firstName :: String,
|
||||||
|
lastName :: String,
|
||||||
|
subject :: String,
|
||||||
|
scores :: [Int]
|
||||||
|
}
|
||||||
|
deriving (Show)
|
||||||
|
|
||||||
-- averages :: [Entry] -> [(String, Float)]
|
-- Parse CSV content into entries
|
||||||
|
parse :: String -> [Entry]
|
||||||
|
parse content =
|
||||||
|
let lns = lines content
|
||||||
|
(header : rows) = lns
|
||||||
|
in map parseRow rows
|
||||||
|
where
|
||||||
|
parseRow line =
|
||||||
|
let fields = split ',' line
|
||||||
|
[fn, ln, subj] = take 3 fields
|
||||||
|
pts = map read (drop 3 fields) :: [Int]
|
||||||
|
in Entry fn ln subj pts
|
||||||
|
|
||||||
-- content -> Entries
|
-- Calculate averages per subject
|
||||||
-- parse :: String -> [Entry]
|
averages :: [Entry] -> [(String, Float)]
|
||||||
|
averages entries =
|
||||||
|
let grouped = groupBy ((==) `on` subject) (sortOn subject entries)
|
||||||
|
avgPerSubject grp =
|
||||||
|
let subj = subject (head grp)
|
||||||
|
allScores = concat [scores e | e <- grp]
|
||||||
|
avg = fromIntegral (sum allScores) / fromIntegral (length allScores)
|
||||||
|
in (subj, avg)
|
||||||
|
in map avgPerSubject grouped
|
||||||
|
|
||||||
|
-- Find the best student (most accumulated points)
|
||||||
|
bestStudent :: [Entry] -> (String, Int)
|
||||||
|
bestStudent entries =
|
||||||
|
let best = maximum [(sum (scores e), firstName e ++ " " ++ lastName e) | e <- entries]
|
||||||
|
in (snd best, fst best)
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
putStrLn "Enter a filename: "
|
putStrLn "Enter a filename: "
|
||||||
putStrLn "..."
|
filename <- getLine
|
||||||
|
content <- readFile filename
|
||||||
|
let entries = parse content
|
||||||
|
(name, points) = bestStudent entries
|
||||||
|
avgs = averages entries
|
||||||
|
putStrLn $ "Best student: " ++ name ++ " (" ++ show points ++ " points)"
|
||||||
|
putStrLn "Average points per subject:"
|
||||||
|
mapM_ (\(subj, avg) -> putStrLn $ " " ++ subj ++ ": " ++ show avg) avgs
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue