grade_report.hs en Haskell
Promedia los puntajes de cada estudiante, asigna nota con letra e imprime una tabla ordenada con resumen del curso.
import Data.List (sortOn)
import Data.Ord (Down (..))
students :: [(String, [Int])]
students =
[ ("Ada", [92, 88, 95, 79])
, ("Bruno", [71, 64, 80, 77])
, ("Chen", [88, 91, 84, 90])
, ("Dara", [55, 48, 58, 51])
, ("Esme", [100, 96, 93, 98])
]
-- An empty score list averages to zero rather than dividing by zero.
average :: [Int] -> Double
average [] = 0
average xs = fromIntegral (sum xs) / fromIntegral (length xs)
-- Guards read as a table of cutoffs, checked from the top down.
letterFor :: Double -> Char
letterFor avg
| avg >= 90 = 'A'
| avg >= 80 = 'B'
| avg >= 70 = 'C'
| avg >= 60 = 'D'
| otherwise = 'F'
-- Round to one decimal by scaling into Int and splitting the digits.
oneDecimal :: Double -> String
oneDecimal x = show whole ++ "." ++ show frac
where
(whole, frac) = round (x * 10) `divMod` (10 :: Int)
pad :: Int -> String -> String
pad n s = s ++ replicate (n - length s) ' '
lpad :: Int -> String -> String
lpad n s = replicate (n - length s) ' ' ++ s
row :: (String, [Int]) -> String
row (name, scores) =
pad 8 name ++ lpad 7 (oneDecimal avg) ++ lpad 7 [letterFor avg]
where
avg = average scores
rule :: String
rule = replicate 22 '-'
main :: IO ()
main = do
let ranked = sortOn (Down . average . snd) students
classAvg = average (concatMap snd students)
passing = length [s | s <- students, average (snd s) >= 60]
putStrLn "term grades, best first"
putStrLn (pad 8 "student" ++ lpad 7 "average" ++ lpad 7 "grade")
putStrLn rule
mapM_ (putStrLn . row) ranked
putStrLn rule
putStrLn (pad 8 "class" ++ lpad 7 (oneDecimal classAvg)
++ lpad 7 [letterFor classAvg])
putStrLn (show passing ++ " of " ++ show (length students) ++ " passing")
Cómo funciona
averagedividefromIntegral (sum xs)entre el conteo y responde cero para una lista vacía.letterForelige la nota con guardas, probando primeroavg >= 90 = 'A'y cayendo hastaotherwise.sortOn (Down . average . snd)pone al mejor primero, yoneDecimalredondea escalando a Int y partiendo condivMod.
Palabras clave y builtins usados aquí
CharDoubleDownIOIntStringdoimportletwhere
El intento, en números
- Líneas
- 60
- Caracteres a escribir
- 1663
- Tokens
- 419
- Ritmo de tres estrellas
- 75 tpm
Al ritmo de tres estrellas de 75 tokens por minuto, este intento toma unos 335 segundos.
Paso 2 de 3 en Bis; paso 26 de 27 en Fundamentos del lenguaje.