typestar

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

  1. Grade.letter is four guarded clauses, one per grade band.
  2. row rounds each average and pads name, number, and letter into columns.
  3. Enum.flat_map pools every quiz so the class average counts each one under the rule.

Keywords and builtins used here

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.

Type this snippet

Step 2 of 3 in Encore, step 26 of 27 in Language basics.

← Previous Next →