Page 1 of 2

mapcar or notmapcar

Posted: Tue Aug 31, 2010 8:44 pm
by burton
hi,im trying to get the following:
the input is a list of numbers (integers eg. (1 2 3 4) (5 6 7 8)) and the expected output is ((1*5)+(2*6)+(3*7)+(4*8))/(the sum of the second list).
is there a non-recursive way of solving it?


> (mapcar #'list '(1 2 3 4) '(5 6 7 8))
((1 5) (2 6) (3 7)(4 8))

i was thinking about mapcar, which would do the trick with a little tweaking, but how?
any ideas?
thanks

Re: mapcar or notmapcar

Posted: Tue Aug 31, 2010 8:59 pm
by Duke
Yeah, you want MAPCAR. What you do not want is #'LIST. ;)
You'll also need one or two REDUCEs (or APPLYs) to get the sums.

Re: mapcar or notmapcar

Posted: Tue Aug 31, 2010 9:56 pm
by Tom
Using MAPCAR and REDUCE is fine. As an alternative approach, you could LOOP.

Code: Select all

(defun notmapcar (list1 list2)
  "(list1 x list2) / Sum(list2)"
  (if (= (length list1) (length list2))
      (loop for val1 in list1
            and val2 in list2
            sum (* val1 val2) into num
            sum val2 into den
            finally (return (/ num den)))
      (error "The lists are not equal in length.")))
There are many ways to iterate in Common Lisp.

Edit: I was about to close down lisp when I just couldn't resist write a version with MAPCAR. It's not totally functional, but it only traverses the lists once.

Code: Select all

(defun tomapcar (list1 list2)
  "(list1 x list2) / Sum(list2)"
  (let ((num 0)
        (den 0))
    (mapcar (lambda (n1 n2)
              (incf num (* n1 n2))
              (incf den n2))
            list1
            list2)
    (/ num den)))

~ Tom

Re: mapcar or notmapcar

Posted: Wed Sep 01, 2010 4:55 am
by Tordmor
Duke wrote:Yeah, you want MAPCAR. What you do not want is #'LIST. ;)
What's wrong with #'list?

Re: mapcar or notmapcar

Posted: Wed Sep 01, 2010 5:03 am
by gugamilare
Tordmor wrote:
Duke wrote:Yeah, you want MAPCAR. What you do not want is #'LIST. ;)
What's wrong with #'list?
It does not do what he wants ;)

Re: mapcar or notmapcar

Posted: Wed Sep 01, 2010 12:55 pm
by Warren Wilkinson

Code: Select all

(defun operation (f-list s-list)
  (/ (reduce #'+ (mapcar #'* f-list s-list)) (reduce #'+ s-list)))

(operation '(1 2 3 4) '(5 6 7 8))  ;; gives 35/13


Re: mapcar or notmapcar

Posted: Wed Sep 01, 2010 4:39 pm
by burton
Warren, is there a way to get decimals as a result instead of a fraction?

Re: mapcar or notmapcar

Posted: Wed Sep 01, 2010 7:01 pm
by gugamilare
You can use the function FLOAT to convert a number (rational or integer) into a float.

Re: mapcar or notmapcar

Posted: Wed Sep 01, 2010 11:26 pm
by Warren Wilkinson
Why would you want floats/decimal numbers? You could opt to use the more accurate rational numbers throughout your code and then use format's "~f" operator to print the result as a floating point number.

Re: mapcar or notmapcar

Posted: Sun Sep 05, 2010 6:08 am
by findinglisp
Warren Wilkinson wrote:Why would you want floats/decimal numbers?
Depends on the code. Floats will generally be handled with greater performance by the hardware; rationals are Lisp-only concepts that have to be manipulated in software, with many extra steps. But as you point out, rationals will keep better precision through a many-step calculation.