patternMinor
"Skewed" average in Lisp
Viewed 0 times
skewedaveragelisp
Problem
I set myself the task to calculate the average of a list, but with two conditions:
So the "skewed" average of the list
I wrote 2 functions that do that. Please review and comment.
Also, how should errors be treated? Imagine passing an empty list to the functions; or a list with all negative numbers.
- negative numbers are ignored
- numbers greater than 100 are counted as if they were 100
So the "skewed" average of the list
'(1 -3 42 297 14) should be (1 + 42 + 100 + 14) / 4 (157/4).I wrote 2 functions that do that. Please review and comment.
(defun skewed-average1 (list)
"calculate average by summing and dividing"
(let ((sum 0) (n 0))
(dolist (x list)
(if (>= x 0)
(progn
(if (> x 100) (setf x 100))
(setf sum (+ x sum))
(setf n (+ 1 n)))))
(/ sum n)))
(defun skewed-average2 (list)
"calculate average by building 'fixed' list"
(let (newlist)
(dolist (x list)
(if (>= x 0)
(progn
(if (> x 100) (setf x 100))
(setf newlist (cons x newlist)))))
(/ (apply #'+ newlist) (length newlist))))
(let ((numbers '(1 -3 42 297 14)))
(print (skewed-average1 numbers))
(print (skewed-average2 numbers)))
Also, how should errors be treated? Imagine passing an empty list to the functions; or a list with all negative numbers.
Solution
(defun skewed-average1 (list)
"calculate average by summing and dividing"
(let ((sum 0) (n 0))
(dolist (x list)
(if (>= x 0)
(progn
(if (> x 100) (setf x 100))
(setf sum (+ x sum))
(setf n (+ 1 n)))))
(/ sum n)))IF ... PROGN is WHEN.>= 0 is plusp.(setf sum (+ ... is INCF.(defun skewed-average1 (list &aux (sum 0) (n 0))
"calculate average by summing and dividing"
(dolist (x list (when (plusp n)
(/ sum n)))
(when (plusp x)
(incf sum (min x 100))
(incf n))))Next function:
(setf newlist (cons x newlist)) is (push x newlist).Don't use
APPLY, use REDUCE. APPLY has a list length limit.Alternative implementations:
(defun skewed-average3 (list)
(loop for x in list
when (plusp x)
sum (min x 100) into sum1
and count t into count1
finally (return (when (plusp count1)
(/ sum1 count1)))))
(defun skewed-average4 (list)
(let ((new-list (remove-if #'minusp
(substitute-if 100
(lambda (item) (> item 100))
list))))
(when new-list
(/ (reduce #'+ new-list)
(length new-list)))))Code Snippets
(defun skewed-average1 (list)
"calculate average by summing and dividing"
(let ((sum 0) (n 0))
(dolist (x list)
(if (>= x 0)
(progn
(if (> x 100) (setf x 100))
(setf sum (+ x sum))
(setf n (+ 1 n)))))
(/ sum n)))(defun skewed-average1 (list &aux (sum 0) (n 0))
"calculate average by summing and dividing"
(dolist (x list (when (plusp n)
(/ sum n)))
(when (plusp x)
(incf sum (min x 100))
(incf n))))(defun skewed-average3 (list)
(loop for x in list
when (plusp x)
sum (min x 100) into sum1
and count t into count1
finally (return (when (plusp count1)
(/ sum1 count1)))))
(defun skewed-average4 (list)
(let ((new-list (remove-if #'minusp
(substitute-if 100
(lambda (item) (> item 100))
list))))
(when new-list
(/ (reduce #'+ new-list)
(length new-list)))))Context
StackExchange Code Review Q#98035, answer score: 4
Revisions (0)
No revisions yet.