"Skewed" average in Lisp I set myself the task to calculate the average of a list, but with two conditions:


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 (&gt;= x 0)
                (progn
                    (if (&gt; 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 (&gt;= x 0)
                (progn
                    (if (&gt; 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.
(defun skewed-average1 (list)
  "calculate average by summing and dividing"
  (let ((sum 0) (n 0))
    (dolist (x list)
      (if (&gt;= x 0)
          (progn
            (if (&gt; x 100) (setf x 100))
            (setf sum (+ x sum))
            (setf n (+ 1 n)))))
    (/ sum n)))


IF ... PROGN  is WHEN.

&gt;= 0 is plusp.

(setf sum (+ ... is INCF.

(defun skewed-average1 (list &amp;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) (&gt; item 100))
                                            list))))
    (when new-list
      (/ (reduce #'+ new-list)
         (length new-list)))))