typestar

grade_report.clj in Clojure

Averages three test scores per student, assigns a letter grade, and closes with a class summary.

;; Term grade report for one small section.
(def roster
  [{:student "Alvarez" :scores [88 92 79]}
   {:student "Byrne"   :scores [71 65 74]}
   {:student "Chao"    :scores [95 98 91]}
   {:student "Dubois"  :scores [59 66 62]}
   {:student "Egan"    :scores [82 85 80]}
   {:student "Farkas"  :scores [48 55 51]}])

;; Dividing by a double keeps the result out of ratio arithmetic.
(defn average [xs]
  (if (seq xs)
    (/ (reduce + xs) (double (count xs)))
    0.0))

;; cond tries its test/result pairs in order and stops at the first
;; true test, so each band only needs its lower bound.
(defn letter [avg]
  (cond
    (>= avg 90) "A"
    (>= avg 80) "B"
    (>= avg 70) "C"
    (>= avg 60) "D"
    :else       "F"))

;; for is a comprehension, not a loop: it returns a new sequence.
(def graded
  (for [{:keys [student scores]} roster
        :let [avg (average scores)]]
    {:student student :avg avg :grade (letter avg)}))

(println (format "%-10s %6s %5s" "STUDENT" "AVG" "GRADE"))
(println (apply str (repeat 23 "-")))
(doseq [{:keys [student avg grade]} (sort-by :student graded)]
  (println (format "%-10s %6.1f %5s" student avg grade)))
(println (apply str (repeat 23 "-")))
(println (format "%-10s %6.1f" "CLASS" (average (map :avg graded))))
(println (format "%-10s %6d" "PASSING"
                 (count (remove #(= "F" (:grade %)) graded))))

How it works

  1. (/ (reduce + xs) (double (count xs))) averages the scores, and the double call keeps the result out of ratio arithmetic.
  2. letter uses a cond running from (>= avg 90) down to :else, so each band states only its lower bound.
  3. (for [{:keys [student scores]} roster destructures every entry, and :let [avg (average scores)] computes the average once per student.

Keywords and builtins used here

The run, in numbers

Lines
39
Characters to type
1277
Tokens
275
Three-star pace
75 tpm

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

Type this snippet

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

← Previous Next →