Skip to content

Instantly share code, notes, and snippets.

@svetlyak40wt
Last active June 22, 2021 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save svetlyak40wt/56a29b6533fbe3332728c546776da381 to your computer and use it in GitHub Desktop.
Save svetlyak40wt/56a29b6533fbe3332728c546776da381 to your computer and use it in GitHub Desktop.
Common Lisp function to put data into buckets and print historgram
;; License BSD
(defpackage #:histogram
(:use #:cl)
(:export
#:print-histogram))
(in-package histogram)
(defun min-value (values)
"Ищет минимальное по любому количеству элементов."
(- (loop for value in values
minimizing value)
;; Чуть чуть сместим концы границы, чтобы точно всё влезло
0.01))
(defun max-value (values)
"Ищет максимальное по любому количеству элементов."
(+ (loop for value in values
maximizing value)
0.01))
(defun print-histogram (data &key
(num-buckets 40)
(width 40) ;; number of symbols in a chart for the largest bucket
min-value
max-value
(as-percents t)
(stream *standard-output*))
(let* ((min-value (or min-value
(min-value (coerce data 'list))))
(max-value (or max-value
(max-value (coerce data 'list))))
(step (/ (- max-value min-value)
(- num-buckets 1)))
(buckets (make-array num-buckets :initial-element 0)))
(flet ((add-value-to-the-bucket (value)
"Finds a bucket for the value and increments it's counter."
(when (<= min-value value max-value)
(let ((index (floor (/ (- value min-value)
step))))
(incf (aref buckets index)))))
(make-bar (number width label)
"Prints a line filled with = symbol with the label at the end."
(if (zerop width)
(format stream "~10<~,2F~>:~%"
number)
(format stream "~10<~,2F~>: ~a ~a~%"
number
(coerce (make-array width :initial-element #\=)
'string)
(unless (zerop width)
label)))))
;; Now add all data points to their buckets
(mapc #'add-value-to-the-bucket
(coerce data 'list))
;; And print bucket values as a ASCII chart
(let ((max-bucket-size
(apply #'max (coerce buckets 'list))))
(loop for value across buckets
for number from min-value to max-value by step
do (make-bar number
(floor (* (/ value max-bucket-size)
width))
(if as-percents
(format nil "~5,2f%" (* (/ value (length data))
100))
value)))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment