1
0
Fork 0
pr3-sose2026-fork/haskell/08-statistics/statistics.hs

64 lines
1.8 KiB
Haskell

import Data.Function (on)
import Data.List (groupBy, nub, sortOn)
import System.IO
-- separator -> Input -> Separated Input
split :: Char -> String -> [String]
split _ "" = []
split sep str =
let (word, rest) = break (== sep) str
in word : case rest of
[] -> []
(_ : xs) -> split sep xs
-- Data structure for a student entry
data Entry = Entry
{ firstName :: String,
lastName :: String,
subject :: String,
scores :: [Int]
}
deriving (Show)
-- 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
-- Calculate averages per subject
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 = do
putStrLn "Enter a filename: "
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