43 lines
1.6 KiB
Common Lisp
43 lines
1.6 KiB
Common Lisp
(defun buckets (numbers)
|
|
(loop with min = (apply #'min numbers)
|
|
with max = (apply #'max numbers)
|
|
with width = (/ (- max min) 7)
|
|
for base from (- min (/ width 2)) by width
|
|
repeat 8
|
|
collect (cons base (+ base width))))
|
|
|
|
(defun bucket-for-number (number buckets)
|
|
(loop for i from 0
|
|
for (min . max) in buckets
|
|
when (and (<= min number) (< number max))
|
|
return i))
|
|
|
|
(defun sparkline (numbers)
|
|
(loop with buckets = (buckets numbers)
|
|
with sparks = "▁▂▃▄▅▆▇█"
|
|
with sparkline = (make-array (length numbers) :element-type 'character)
|
|
with min = (apply #'min numbers)
|
|
with max = (apply #'max numbers)
|
|
for number in numbers
|
|
for i from 0
|
|
for bucket = (bucket-for-number number buckets)
|
|
do (setf (aref sparkline i) (char sparks bucket))
|
|
finally (format t "Min: ~A, Max: ~A, Range: ~A~%" min max (- max min))
|
|
(write-line sparkline)))
|
|
|
|
(defun string->numbers (string)
|
|
(flet ((delimiterp (c)
|
|
(or (char= c #\Space) (char= c #\,))))
|
|
(loop for prev-end = 0 then end
|
|
while prev-end
|
|
for start = (position-if-not #'delimiterp string :start prev-end)
|
|
for end = (position-if #'delimiterp string :start start)
|
|
for number = (read-from-string string t nil :start start :end end)
|
|
do (assert (numberp number))
|
|
collect number)))
|
|
|
|
(defun string->sparkline (string)
|
|
(sparkline (string->numbers string)))
|
|
|
|
(string->sparkline "1 2 3 4 5 6 7 8 7 6 5 4 3 2 1")
|
|
(string->sparkline "1.5, 0.5 3.5, 2.5 5.5, 4.5 7.5, 6.5")
|