typestar

grade_report.scala in Scala

Per-student averages, letter grades and a class summary from an inline roster.

// A per-student grade report from an inline roster.

case class Student(name: String, scores: List[Int])

val roster: List[Student] = List(
  Student("Ada Byron", List(92, 88, 100, 95)),
  Student("Grace Hopper", List(78, 84, 80, 91)),
  Student("Alan Turing", List(65, 72, 58, 70)),
  Student("Katherine J.", List(99, 97, 94, 100)),
  Student("Edsger D.", List(55, 61, 49, 64)),
)

def average(scores: List[Int]): Double =
  if scores.isEmpty then 0.0 else scores.sum.toDouble / scores.size

// Guards turn one match into a ladder of thresholds, read top down,
// so the first case that fits wins.
def letter(avg: Double): String = avg match
  case a if a >= 90 => "A"
  case a if a >= 80 => "B"
  case a if a >= 70 => "C"
  case a if a >= 60 => "D"
  case _            => "F"

@main def gradeReport(): Unit =
  val graded = roster.map(s => (s, average(s.scores)))
  // Best first, so the ranking is visible without reading averages.
  val ranked = graded.sortBy((_, avg) => -avg)

  println(f"${"student"}%-14s${"best"}%6s${"worst"}%6s${"avg"}%7s${"grade"}%7s")
  println("-" * 40)
  for (student, avg) <- ranked do
    val best = student.scores.max
    val worst = student.scores.min
    println(f"${student.name}%-14s$best%6d$worst%6d$avg%7.1f${letter(avg)}%7s")

  val classAvg = graded.map((_, avg) => avg).sum / graded.size
  val passing = graded.count((_, avg) => avg >= 60)
  println("-" * 40)
  println(f"class average $classAvg%.1f (${letter(classAvg)})")
  println(s"$passing of ${roster.size} students passing")

How it works

  1. average divides scores.sum.toDouble by the number of scores.
  2. letter reads as a ladder of thresholds through guards such as case a if a >= 90.
  3. sortBy((_, avg) => -avg) puts the best first, and ${student.name}%-14s pads each name to a fixed column.

Keywords and builtins used here

The run, in numbers

Lines
41
Characters to type
1469
Tokens
388
Three-star pace
75 tpm

At the three-star pace of 75 tokens a minute, this run takes about 310 seconds.

Type this snippet

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

← Previous Next →