DEV Community


Discussion on: Daily Challenge #4 - Checkbook Balancing

johncip profile image
jmc • Edited

I'm impressed by how short many of the solutions are.


(ns checkbook
  (:require [clojure.string :refer [join split]]))

;; split line into tokenized "entry"
(defn tokens [line]
  (map read-string (re-seq #"(?:\w|\.)+" line)))

;; append running balance onto entries
(defn with-running-balance [[start & entries]]
    (fn [acc entry]
      (let [prev-bal  (last (last acc))
            cur-bal   (- prev-bal (last entry))
            new-entry (conj (vec entry) "Balance" cur-bal)]
        (conj acc new-entry)))
    [["Original_Balance" (last start)]]

;; output entry as string, with numbers rounded
(defn format-entry [xs]
  (case (count xs)
    2 (apply format "%s %.2f" xs)
    5 (apply format "%s %s %.2f %s %.2f" xs)))

;; append running balance, include total & average, format nums
(defn balance [s]
  (let [lines   (split s #"\n")
        entries (map tokens lines)
        $$      (map last (rest entries))]
    (join "\n"
      (map format-entry
        (conj (with-running-balance entries)
              ["Total expense" (apply + $$)]
              ["Average expense" (/ (apply + $$) (count $$))])))))