TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: rhino on January 02, 2014, 05:44:27 AM

Title: mapcar help
Post by: rhino on January 02, 2014, 05:44:27 AM
Hi All,

This snippet:
Code - Text: [Select]
  1. (mapcar '+ '(0.0 200.0 0.0) p1)
will add 200 to a point list p1.

How do I apply this to each item in a list with multiple points.

I tried:
Code - Text: [Select]
  1. (foreach n dplist (mapcar '+ '(0.0 200.0 0.0) n))
but that will return a list with the last point only by applying mapcar
Title: Re: mapcar help
Post by: roy_043 on January 02, 2014, 06:21:11 AM
Code - Auto/Visual Lisp: [Select]
  1.   '(lambda (dp)
  2.     (mapcar '+ '(0.0 200.0 0.0) dp)
  3.   )
  4.   dplist
  5. )
Title: Re: mapcar help
Post by: rhino on January 02, 2014, 07:10:10 AM
Thanks Roy! I was trying lambda but not by doubling the mapcar - this makes sense though hehe  ^-^
Title: Re: mapcar help
Post by: Bhull1985 on January 02, 2014, 08:20:29 AM
Roy would you mind to comment each line out there in what's happening, for newbies like me who wish to further their understanding of mapcar
(and eventually be able to use it constructively within code!)
Title: Re: mapcar help
Post by: CAB on January 02, 2014, 09:08:58 AM
----------  Mapcar  Lambda  Apply   ------------
http://www.theswamp.org/index.php?topic=2953.0   (MP)
http://www.theswamp.org/index.php?topic=340.0   (CAB)
http://www.cadtutor.net/forum/showthread.php?52127-Mapcar-lambda-Description
http://lee-mac.com/mapcarlambda.html
Title: Re: mapcar help
Post by: CAB on January 02, 2014, 09:10:35 AM
While you are studying you may find this useful as well.
-------------  LISP  Logic  -----------------
http://www.theswamp.org/index.php?topic=13046.msg158557#msg158557  by CAB
http://www.cadtutor.net/forum/showthread.php?52365-localizing-variables

Title: Re: mapcar help
Post by: roy_043 on January 02, 2014, 09:26:39 AM
Thank you CAB!
Title: Re: mapcar help
Post by: CAB on January 02, 2014, 09:41:17 AM
You're quite welcome.  8)
Title: Re: mapcar help
Post by: Bhull1985 on January 02, 2014, 01:03:42 PM
I have read most of the longer mapcar and lambda references that reside on this board indeed :)
The ones that come to mind just from memory are irneb and lee mac, they established a good basis in understanding the functions but I still have yet to learn how to properly apply them, and as thus I hassle more experienced lispers to explain what they're doing in hopes of gaining that knowledge.
However, instead of perusing the boards I'll spend some time with what you've linked, maybe there's something I haven't seen :D
Thank you both, regardless!!
Title: Re: mapcar help
Post by: Lee Mac on January 02, 2014, 01:56:45 PM
IMO, the key way to think about how to apply mapcar/lambda is to think about exactly what you want to do with each list item - when you know the function that is to be applied to each item, you can simply pass this function to mapcar to evaluate it on all items in the list.

In this particular case, we already know the operation that is to be applied to each item:
Code: [Select]
(mapcar '+ '(0.0 200.0 0.0) <list-item>)
And so we can construct a function to perform this operation either using defun or lambda:
Code: [Select]
(defun myfunction ( x )
    (mapcar '+ '(0.0 200.0 0.0) x)
)
Code: [Select]
(lambda ( x ) (mapcar '+ '(0.0 200.0 0.0) x))Think of the lambda function simply as a function defined without a function name - an anonymous function.

Each of the above functions require a single argument 'x' (the list item) and will perform the required operation on this item and return the result of the operation.

Now to apply this function on all list items (and return the results), it becomes a simple case of supplying the function to mapcar:
Code: [Select]
(mapcar 'myfunction <list>)
Code: [Select]
(mapcar '(lambda ( x ) (mapcar '+ '(0.0 200.0 0.0) x)) <list>)
To understand why the function has been quoted, see this tutorial (http://bit.ly/18ftLyF).

Lee
Title: Re: mapcar help
Post by: rhino on January 02, 2014, 02:04:05 PM
Hi Bhull1985,

The really great thing with AutoLISP is that you can test out the functions and methods directly in VLIDE using the visual lisp console.

I couldn't wrap my head around mapcar or lambda too - in spite of reading through those tutorial; I would just go huh! :ugly:

But here's how I came up with the first function:
Code - Text: [Select]
  1. (mapcar '+ '(0.0 200.0 0.0) p1)
I got this by reapplying the logic in the below example from http://www.lee-mac.com/mapcarlambda.html (http://www.lee-mac.com/mapcarlambda.html):
Quote
Code - Text: [Select]
  1. (mapcar '+ '(1 2 3 4 5) '(3 4 5 6 7))
  2. (4 6 8 10 12)
Here mapcar is supplied with the + function, which takes any number of numerical arguments and adds them together. Hence in the above example, mapcar will evaluate the + function on each member of each list and return a list of the results:
Code - Text: [Select]
  1. (4 6 8 10 12) = ((+ 1 3) (+ 2 4) (+ 3 5) (+ 4 6) (+ 5 7))

so effectively the first mapcar line is a function to add to a supplied list. edit: list with one point

just before roy could post the solution I was reading and trying to apply this logic as per CAB's explainationhttp://www.theswamp.org/index.php?topic=340.0 (http://www.theswamp.org/index.php?topic=340.0):

Quote
mapcar is a specialized foreach function
defined as
(mapcar function list1... listn)
Quote
Lambda: defined as
(lambda arguments expr...)
Code - Auto/Visual Lisp: [Select]
  1. (setq counter 0)
  2. (mapcar '(lambda (x)  
  3.           (setq counter (1+ counter))  
  4.           (* x 5)  
  5.         )  
  6.         '(2 4 -6 10.2)  
  7. )
mapcar feeds each value from the list (2 4 -6 10.2) to x then collects the return values in a list
the (setq counter (1+ counter)) counts the number of times the lambda was executed which will be 4
  this also illustrates that more than one line of code may be used within the lambda function
the ' symbol could be replaced with (function and would perform better (faster).
the (* x 5) process the x variable as follows
  (* 2 5)  10
  (* 4 5)  20
  (* -6 5) -30
  (* 10.2 5) 51
so it return
   (10 20 -30 51.0)

which is what is happening with the code roy posted:
Code - Auto/Visual Lisp: [Select]
  1. ;apply function on multiple entities in a list
  2.      '(lambda (dp) ;;dp is the each item in the list
  3.        (mapcar '+ '(0.0 200.0 0.0) dp) ;;function
  4.      )
  5.      dplist ;;main list to apply the function
  6.     )

Hope that helps you out and happy coding!
Title: Re: mapcar help
Post by: Bhull1985 on January 02, 2014, 03:36:09 PM
Alright thanks guys, really delved into this one this afternoon.
Even reached a gem from MIT :
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-10.html#%_sec_1.1.6
Exercice 1.3, therin, was fun to do.
Simply
Quote
Exercise 1.3.  Define a procedure that takes three numbers as arguments and returns the sum of the squares of the two larger numbers.
MIT so, no answers, this is what I came up with
Code: [Select]
(defun summed ( x1 x2 x3 / n1 n2 data)
(setq n1 (if (> x1 x2)
                 (* x1 x1)
                 (* x2 x2)
             );if
);setq
(setq n2 (if (> x1 x3)
                 (* x1 x1)
                 (* x3 x3)
             );if
);setq
(setq data (+ n1 n2))
)
Quick paste into cad and i'm pleasantly being returned these:
Quote
(_> (setq data (+ n1 n2)))
SUMMED
Command: (summed 1 2 3)
13
Command: (summed 2 4 3)
25

But alas, that's not mapcar, nor lambda. However, I did learn a crucial fact in understanding these that is often not touched on, I suppose it's one of those "taken for granted" or "should be fundamentally understood". That said, and being self-taught, I missed out until now on the fact that the original list is always within the mapcar statement, in fact it's the second argument so it has to be. Function to be applied to the list being the first. If the list is given in '(L I T E R A L) form or given as a variable1 has no affect on the function that is being applied to the list.
This is where I have to force myself to be careful. It won't be simple addition that a mapcar is accomplishing, as per 95% of the examples given with it. I understand the need for simplicity but it's confusing in it's own right :P
I'll have to take them symbolically in order to interchange the arithmetic with useful programming skills, for instance
Code: [Select]
(setq pt1 '(1.5 2.5 3.5))
(setq pt2 '(2.0 3.0 4.0))
(setq pt3 '(3.5 4.5 5.5))
(setq lst '(pt1 pt2 pt3) )

(defun getx ( pt /)
(if pt
(princ (car pt))
)
(princ)
)

(mapcar
'(lambda ( pt ) (if pt (princ (car pt)))
lst
)
Fails. Miserably. I thought that would work, when substituting lambda for the function that works if I do it (getx pt1) with those points defined.
Bah, need a short break, few hrs of this and an error. Try more soon..
Title: Re: mapcar help
Post by: Lee Mac on January 02, 2014, 04:01:52 PM
Quote
Exercise 1.3.  Define a procedure that takes three numbers as arguments and returns the sum of the squares of the two larger numbers.
MIT so, no answers, this is what I came up with
Code: [Select]
(defun summed ( x1 x2 x3 / n1 n2 data)
(setq n1 (if (> x1 x2)
                 (* x1 x1)
                 (* x2 x2)
             );if
);setq
(setq n2 (if (> x1 x3)
                 (* x1 x1)
                 (* x3 x3)
             );if
);setq
(setq data (+ n1 n2))
)

Careful... observe:
Code: [Select]
_$ (summed 1 2 3)
13
_$ (summed 3 2 1)
18

Here's one possible way to tackle it (using mapcar):
Code: [Select]
(defun sumsqr ( x y z / l )
    (setq l (list x y z)
          l (mapcar '* l l)
    )
    (apply 'max (mapcar '+ (cons (last l) l) l))
)

I'll have to take them symbolically in order to interchange the arithmetic with useful programming skills, for instance
Code: [Select]
(setq pt1 '(1.5 2.5 3.5))
(setq pt2 '(2.0 3.0 4.0))
(setq pt3 '(3.5 4.5 5.5))
(setq lst '(pt1 pt2 pt3) )

(defun getx ( pt /)
(if pt
(princ (car pt))
)
(princ)
)

(mapcar
'(lambda ( pt ) (if pt (princ (car pt)))
lst
)
Fails. Miserably. I thought that would work, when substituting lambda for the function that works if I do it (getx pt1) with those points defined.

Here's your problem:
Code: [Select]
(setq lst '(pt1 pt2 pt3))
See this section (http://lee-mac.com/quote.html#variable) of my tutorial.
Title: Re: mapcar help
Post by: CAB on January 02, 2014, 04:02:03 PM
How about a picture  :)
Title: Re: mapcar help
Post by: Lee Mac on January 02, 2014, 04:09:28 PM
Excellent diagram CAB  :-)
Title: Re: mapcar help
Post by: Lee Mac on January 02, 2014, 04:20:26 PM
Quote
Exercise 1.3.  Define a procedure that takes three numbers as arguments and returns the sum of the squares of the two larger numbers.

Without using mapcar:
Code - Auto/Visual Lisp: [Select]
  1. (defun sumsqr ( x y z )
  2.     (cond ((or (<= x y z) (<= x z y))
  3.            (+ (* y y) (* z z)))
  4.           ((or (<= y x z) (<= y z x))
  5.            (+ (* x x) (* z z)))
  6.           ((+ (* x x) (* y y)))
  7.     )
  8. )
Code - Auto/Visual Lisp: [Select]
  1. (defun sumsqr ( x y z / m )
  2.     (setq m (min x y z))
  3.     (cond ((= x m) (+ (* y y) (* z z)))
  4.           ((= y m) (+ (* x x) (* z z)))
  5.           ((+ (* x x) (* y y)))
  6.     )
  7. )
Title: Re: mapcar help
Post by: Bhull1985 on January 02, 2014, 04:22:32 PM
Darn, thought I had that one correct.
Well thanks for showing me what I need to study up on you guys!

Oh I really like the second method you used there with min. Perfect example of how experience is key so I went and commented it, committing it to memory best I can

Code: [Select]
(defun sumsqr ( x y z / m)               ;define
(setq m (min x y z))                        ;sets a variable m to be equal to the lowest of the three values
(cond ((= x m) (+ (* y y) (* z z)))   ;checks if x is lowest, thereby qualifying y and z, add the sqrts
         ((= y m) (+ (* x x) (* z z)))   ;checks if y is lowest, thereby qualifying x and z, add the sqrts
         ((+ (* x x) (* y y)))               ;otherwise z must be lowest therefor x and y are qualified, add the sqrts
)                                                    ;cond
)                                                    ;defun
Title: Re: mapcar help
Post by: Lee Mac on January 02, 2014, 04:37:45 PM
Thank you Brandon - judging by your comments, it looks like you understand it well  :-)
Title: Re: mapcar help
Post by: Lee Mac on January 02, 2014, 04:43:53 PM
Another for fun:
Code - Auto/Visual Lisp: [Select]
  1. (defun sumsqr ( x y z / l )
  2.     (apply '+ (mapcar '* (setq l (cdr (vl-sort (list x y z) '<))) l))
  3. )
Title: Re: mapcar help
Post by: Lee Mac on January 02, 2014, 04:45:27 PM
A recursive variation:
Code - Auto/Visual Lisp: [Select]
  1. (defun sumsqr ( x y z )
  2.     (if (= x (min x y z)) (+ (* y y) (* z z)) (sumsqr y z x))
  3. )
Title: Re: mapcar help
Post by: Bhull1985 on January 02, 2014, 05:07:29 PM
Another for fun:
Code - Auto/Visual Lisp: [Select]
  1. (defun sumsqr ( x y z / l )
  2.     (apply '+ (mapcar '* (setq l (cdr (vl-sort (list x y z) '<))) l))
  3. )

Code: [Select]
(defun sumsqr ( x y z / l )              ;define, 3 arguments
(apply                                          ;apply the following
  '+                                              ;add the results together
     (mapcar                                  ;do the following function to each item in the following list
          '*                                       ;telling the mapcar to multiply the values found in the following list by the values of the supplied list
              (setq l (cdr
                           (vl-sort (list x y z) '<)               ;seems like cheating but you used an active-x vl-sort, gave it the list, then told it what to sort by "less than" this places the smallest value in the
                                                                          ;first position in the list, which is why you call (cdr) in the next nested statement, this in effect "finds" the two greatest numbers. Cheater.
                        )                     
               );set a variable 'l' to contain the two larger numbers

           l                                                                ;2nd argument to mapcar, the list to be multiplied BY. These two lists are the same. This squares them

    )          ;the nesting makes it complicated but obviously the (apply '+ (* l l)) has the squares added together.
)

well, obviously I've still got some learning to do but I think i'm getting there. A lot further than I was this morning, that's for sure.
Heading out for the day in a few minutes, enjoy your weekend everyone.
Oh and I was just kidding Lee (about the cheating), your ability to provide alternative methods of accomplishing the same task is as usual, very impressive.
One day I hope to have as great an understanding as you do.
Title: Re: mapcar help
Post by: Lee Mac on January 02, 2014, 06:11:42 PM
Code: [Select]
Cheater.

:-D

well, obviously I've still got some learning to do but I think i'm getting there. A lot further than I was this morning, that's for sure.
Heading out for the day in a few minutes, enjoy your weekend everyone.

Oh and I was just kidding Lee (about the cheating), your ability to provide alternative methods of accomplishing the same task is as usual, very impressive.

One day I hope to have as great an understanding as you do.

Don't worry - I saw the funny side of your comments  :-)
For the record, I also think its cheating  :lol:

Thank you for the kind compliments - I'm glad your learning is progressing and I'm happy to offer some food for thought as I very much enjoy writing the examples and finding new ways to tackle problems.

Have a good weekend Brandon  :-)