grade_report.exs in Elixir
Quiz scores fold into averages and letter grades, then into a formatted class report.
# Average quiz scores into letter grades and print the class report.
defmodule Grade do
def letter(avg) when avg >= 90, do: "A"
def letter(avg) when avg >= 80, do: "B"
def letter(avg) when avg >= 70, do: "C"
def letter(_avg), do: "retake"
def average(scores), do: Enum.sum(scores) / length(scores)
def row(name, scores) do
avg = average(scores)
shown = avg |> Float.round(1) |> Float.to_string()
String.pad_trailing(name, 9) <>
String.pad_leading(shown, 6) <> " " <> letter(avg)
end
end
roster = [
{"Imani", [92, 88, 95]},
{"Theo", [78, 83, 80]},
{"Sofia", [85, 91, 89]},
{"Miles", [62, 70, 68]}
]
IO.puts(String.pad_trailing("student", 9) <> " avg grade")
IO.puts(String.duplicate("-", 24))
for {name, scores} <- roster do
IO.puts(Grade.row(name, scores))
end
every_score = Enum.flat_map(roster, fn {_name, scores} -> scores end)
class_avg = Enum.sum(every_score) / length(every_score)
IO.puts(String.duplicate("-", 24))
IO.puts("class average: #{Float.round(class_avg, 1)}")
IO.puts("quizzes graded: #{length(every_score)}")
How it works
Grade.letteris four guarded clauses, one per grade band.rowrounds each average and pads name, number, and letter into columns.Enum.flat_mappools every quiz so the class average counts each one under the rule.
Keywords and builtins used here
EnumFloatGradeIOStringdefdefmoduledoendfnfor
The run, in numbers
- Lines
- 38
- Characters to type
- 1038
- Tokens
- 330
- Three-star pace
- 75 tpm
At the three-star pace of 75 tokens a minute, this run takes about 264 seconds.
Step 2 of 3 in Encore, step 26 of 27 in Language basics.