TheSwamp
Code Red => AutoLISP (Vanilla / Visual) => Topic started by: Mark on November 22, 2005, 09:17:56 AM
-
Can you tell me when it's appropriate to use either mapcar or foreach?
-
I use;
- MAPCAR when I need to get LIST.
- FOREACH when I want to do several things to each item on a LIST and I do not require any output and simple I want to process ALL of them to certain function.
HTMSS
-
^^ Same for me.
Here is a quick demo.
Command:
Command: (setq starterlist '(1 2 3 4 5 6 7 8 9))
(1 2 3 4 5 6 7 8 9)
Command: (setq mylist starterlist)
(1 2 3 4 5 6 7 8 9)
Command: (repeat 7 (setq mylist (append starterlist mylist)))
(1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3
4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9)
Command: (setq mapcarlist (mapcar '(lambda (x) (1+ x)) mylist))
(2 3 4 5 6 7 8 9 10 2 3 4 5 6 7 8 9 10 2 3 4 5 6 7 8 9 10 2 3 4 5 6 7 8 9 10 2
3 4 5 6 7 8 9 10 2 3 4 5 6 7 8 9 10 2 3 4 5 6 7 8 9 10 2 3 4 5 6 7 8 9 10)
Command: (setq foreachlist (foreach x mylist (1+ x)))
10
Command: !mapcarlist
(2 3 4 5 6 7 8 9 10 2 3 4 5 6 7 8 9 10 2 3 4 5 6 7 8 9 10 2 3 4 5 6 7 8 9 10 2
3 4 5 6 7 8 9 10 2 3 4 5 6 7 8 9 10 2 3 4 5 6 7 8 9 10 2 3 4 5 6 7 8 9 10)
Command: !foreachlist
10
Command:
-
Lile Luis said / implied, generally speaking -- when I want the result of an operation on a list to return a list I use mapcar, otherwise foreach.
Interestingly, mapcar is frequently used when foreach is actually more appropriate.
Classic example --
(start_list "key")
(mapcar 'add_list items)
(end_list)
Result is discarded.
I suspect it's the brevity of mapcar that frequently inspires it's use.
The foreach equivalent just for completeness --
(start_list "key")
(foreach item items (add_list item))
(end_list)
:)
-
It is somehow what happens to the function REPEAT that [according to my impression] not many are using it anymore [including me] or maybe very little.
-
I use repeat often --
(if (setq ss (ssget))
(repeat (setq i (sslength ss))
(foo (ssname ss (setq i (1- i))))
)
)
-
In addition to what's been said, the other key difference between foreach and mapcar is mapcar accepts multiple list arguments. Foreach only takes one list argument.
As Michael said, which one to use given a single list argument is sometimes a toss up.
-
How about some examples of working with an entity list?
-
Context please.
:)
-
May not be the best example.
(setq ss (ssget "X" '((0 . "TEXT")))
cntr 0
)
(while (setq ent (ssname ss cntr))
;
; pull out significant parts, DXF values 1, 8, 40, 410, etc.
;
(setq cntr (1+ cntr))
)
-
In example change the ename's color to RED
(foreach
ename (list ent1 ent2 ent3)
(setq elist (entget ename))
;; if they are bylayer change to color 1
(if (not (cdr (assoc 62 elist)))
(entmod (append elist (list (cons 62 1))))))
(mapcar '(lambda (obj) (vla-put-color obj acRed))
(mapcar 'vlax-ename->vla-object (list ent1 ent2 ent3)))
-
(if (setq ss (ssget "x" '((0 . "text"))))
(repeat (setq i (sslength ss))
(setq data (entget (ssname ss (setq i (1- i)))))
;;
;; pull out significant parts, DXF values 1, 8, 40, 410, etc.
;;
(print
(mapcar
'(lambda (key) (assoc key data))
'(1 8 40 410)
)
)
(princ)
)
)
-
Sorry don't have time to pen something pretty but perhaps this will illuminate ...
(defun c:CatSkinning ( / ss i keys data )
(setq keys '(8 40 1))
(if (setq ss (ssget "x" '((0 . "text"))))
(repeat (setq i (sslength ss))
(setq data (entget (ssname ss (setq i (1- i)))))
;; mapcar 1
(princ "\nmapcar 1 ...")
(print
(mapcar
'(lambda (key) (assoc key data))
keys
)
)
;; mapcar 2 (not desirable, but for
;; demonstration purposes included)
(princ "\nmapcar 2 ...")
(print
(apply 'append
(mapcar
'(lambda (pair)
(if (member (car pair) keys)
(list pair)
)
)
data
)
)
)
;; vl-remove-if-not
(princ "\nvl-remove-if-not ...")
(print
(vl-remove-if-not
'(lambda (pair) (member (car pair) keys))
data
)
)
;; foreach
(princ "\nforeach ...")
(print
( (lambda ( / result )
(foreach pair data
(if (member (car pair) keys)
(setq result
(cons
pair
result
)
)
)
)
(reverse result)
)
)
)
(princ "\n\n")
)
)
(princ)
)
-
"foreach" can speed things up significantly. Compare these two ways of drawing an ellipse:
This one with use of "foreach"
(defun c:lll (/ osn a b x ip clv clh p1 p2 cpy cpx e1 e2 z plp cc)
; draws ellipse out of polyline
(setq osn (getvar "OSMODE"))
(setvar "cmdecho" 0)
;====================================================================
(if aa
()
(setq aa 1.0)
)
(princ "\n A radius < ") ; short radius
(princ aa)
(princ " > ?? : ")
(initget 6)
(setq a (getdist))
(if (= a nil)
(setq a aa)
)
(setq aa a)
;==================================================================
(if bb
()
(setq bb 2.0)
)
(princ "\n B radius < ")
(princ bb)
(princ " > ?? : ")
(initget 6)
(setq b (getdist))
(if (= b nil)
(setq b bb)
)
(setq bb b)
;==================================================================
(setq x (/ pi 90))
;====================================================================
(setq ip (getpoint "\n Insert : "))
; calc
(setvar "osmode" 0)
(command "line"
(polar ip (* pi 0.5) (* a 1.125))
(polar ip (* pi 1.5) (* a 1.125))
""
)
(setq clv (entlast))
(command "change"
clv
""
"p"
"c"
3
"lt"
"center"
"s"
(/ a 4)
""
)
(command "line"
(polar ip 0 (* b 1.125))
(polar ip pi (* b 1.125))
""
)
(setq clh (entlast))
(command "change"
clh
""
"p"
"c"
3
"lt"
"center"
"s"
(/ a 4)
""
)
(setq p1 (polar ip (* pi 1.5) a))
(setq cpy (polar ip (* pi 1.5) (* a (cos x))))
(setq cpx (polar ip 0 (* b (sin x))))
(setq p2 (list (car cpx) (cadr cpy)))
(command "pline" p1 p2 "")
(setq e1 (entlast))
(setq z (* 2 x))
(while (< z (+ (* 2 pi) (/ z 2)))
(setq plp (cons p2 plp))
(setq cpy (polar ip (* pi 1.5) (* a (cos z))))
(setq cpx (polar ip 0 (* a (sin z) (/ b a))))
(setq p2 (list (car cpx) (cadr cpy)))
(setq z (+ z x))
)
(setq plp (reverse plp))
(command "pline")
(foreach cc plp (command cc))
(command "")
(setq e2 (entlast))
(command "pedit" e1 "j" e2 "" "")
(prompt "\nRotation Angle: ")
(setvar "osmode" osn)
(command "ROTATE" e1 clv clh "" IP pause)
(princ)
)
(prompt "\n Type < LLL > for ellipse")
... and this one stepping through segments of polyline:
(defun c:lll (/ osn a b x ip clv clh p1 p2 cpy cpx e1 e2 z) ; draws ellipse out of polyline
(setq osn (getvar "OSMODE"))
(setvar "cmdecho" 0)
;====================================================================
(if aa
()
(setq aa 1.0)
)
(princ "\n A radius < ") ; short radius
(princ aa)
(princ " > ?? : ")
(initget 6)
(setq a (getdist))
(if (= a nil)
(setq a aa)
)
(setq aa a)
;==================================================================
(if bb
()
(setq bb 2.0)
)
(princ "\n B radius < ")
(princ bb)
(princ " > ?? : ")
(initget 6)
(setq b (getdist))
(if (= b nil)
(setq b bb)
)
(setq bb b)
;==================================================================
;|(if xp ()(setq xp 2))
(princ "\n Precision in degrees [1 - 10] < ")
(princ xp)
(princ " > ?? : ")
(setq x (getint))
(if (> x 10)(setq x 10))
(if (or (= x 3) (= x 4))(setq x 2))
(if (or (= x 7) (= x 8) (= x 9))(setq x 6))
(if (= x nil)(setq x (/ (* xp pi) 180))(setq x (/ (* x pi) 180)))
(setq xp (/ (* x 180) pi))|;
(setq x (/ pi 90))
;====================================================================
(setq ip (getpoint "\n Insert : "))
; calc
(setvar "osmode" 0)
(command "line"
(polar ip (* pi 0.5) (* a 1.125))
(polar ip (* pi 1.5) (* a 1.125))
""
)
(setq clv (entlast))
(command "change"
clv
""
"p"
"c"
3
"lt"
"center"
"s"
(/ a 4)
""
)
(command "line"
(polar ip 0 (* b 1.125))
(polar ip pi (* b 1.125))
""
)
(setq clh (entlast))
(command "change"
clh
""
"p"
"c"
3
"lt"
"center"
"s"
(/ a 4)
""
)
(setq p1 (polar ip (* pi 1.5) a))
(setq cpy (polar ip (* pi 1.5) (* a (cos x))))
(setq cpx (polar ip 0 (* b (sin x))))
(setq p2 (list (car cpx) (cadr cpy)))
(command "pline" p1 "w" 0 0 p2 "")
(setq e1 (entlast))
(setq z (* 2 x))
(while (< z (* 2 pi))
(setq cpy (polar ip (* pi 1.5) (* a (cos z))))
(setq cpx (polar ip 0 (* a (sin z) (/ b a))))
(setq p2 (list (car cpx) (cadr cpy)))
(command "pline" "" "w" 0 0 p2 "")
(setq e2 (entlast))
(command "pedit" e1 "j" e2 "" "")
(setq z (+ z x))
)
(prompt "\nRotation Angle: ")
(setvar "osmode" osn)
(command "ROTATE" e1 clv clh "" IP pause)
(princ)
)
(prompt "\n Type < LLL > for ellipse")
-
Foreach his own, but alas for me is mapcar.
As MP stated I use mapcar more for its brevity.
[sidebar]
MP, it's rather ironic that you used 'ssget' to show that you use 'repeat' quite often when 'foreach' and 'mapcar' can't get 'ssget' entities.
[/sidebar]
-
[sidebar]
MP, it's rather ironic that you used 'ssget' to show that you use 'repeat' quite often when 'foreach' and 'mapcar' can't get 'ssget' entities.
[/sidebar]
In the spirit of fun ...
(defun PicksetToEnames ( ss / i result )
(if (eq 'pickset (type ss))
(repeat (setq i (sslength ss))
(setq result
(cons
(ssname ss (setq i (1- i)))
result
)
)
)
)
)
:)
-
And more fun.
Well you used the "can't" word. he he he
;; CAB 03/22/2005
;; just an exersize
(defun c:TxtC (/ ss elst)
(prompt "\nSelect text objects... <exit> ")
(and (setq ss (ssget '((0 . "TEXT") (72 . 1) (73 . 2))))
(repeat (sslength ss)
(setq elst (entget (ssname ss 0)))
(entmake (list '(0 . "CIRCLE")
(cons 10 (cdr (assoc 11 elst)))
(cons 40 (* (cdr (assoc 40 elst)) 0.06))
)
)
(ssdel (ssname ss 0) ss)
)
)
(princ)
)
-
Here are some samples using mapcar and foreach:
(defun rcmd-divide-vector (pt1 pt2 n)
(mapcar '+
pt1
(mapcar '/
(mapcar '- pt2 pt1)
(list n n n))))
(defun rcmd-transpts (lst pt / p0 p1 ang pin ang pt1 lst1)
(setq p0 (car lst)
p1 (cadr lst)
ang (angle p0 p1)
pin (inters p0 p1 pt (polar pt (+ ang (/ pi 2)) 1) nil)
ang (angle pin pt))
(foreach
p
lst
(setq pt1 (polar p ang (distance pt pin))
lst1 (append lst1 (list pt1))))
lst1)
(defun rcmd-point-member (p lst / tst)
(foreach
pt
lst
(if pt
(if (equal (distance p pt) 0 0.00001)
(setq tst T))))
tst)
(defun rcmd-list->ss (lst / ss0)
(setq ss0 (ssadd))
(foreach n lst (ssadd n ss0))
ss0)
(defun rcmd-point-member (p lst / tst)
(foreach
pt
lst
(if pt
(if (equal (distance p pt) 0 0.00001)
(setq tst T))))
tst)
(defun rcmd-no-equal-points (lst / lst2)
(foreach
pt
lst
(if (not (rcmd-point-member pt lst2))
(setq lst2 (append lst2 (list pt)))))
lst2)
-
another one:
;; string_lst = list of strings
;; flag = max or' min
(defun strlenmm (string_lst flag / lst)
(setq lst (mapcar (function (lambda (x) (cons (strlen x) x)))
string_lst))
(cdr (assoc (apply 'flag (mapcar 'car lst)) lst)))
_$ (strlenmm (list "10000.0" "1.0" "2300000000" "1.234") min)
"1.0"
_$
_$ (strlenmm (list "10000.0" "1.0" "2300000000" "1.234") max)
"2300000000"
_$
-
Will you used the "can't" word. he he he
Maybe I misread that, but I thought he was referring to the fact you can't do
(foreach ent ss ....)
(mapcar 'entget ss)
-
That's the way I read it too Jeff, ergo ..
(foreach ename (PicksetToEnames (ssget "x"))
(foo ename)
)
Or ...
(mapcar 'foo (PicksetToEnames (ssget "x")))
:)
-
OK, i understand now, Little slow on the uptake lately. :lol:
And this doesn't count, right?
(foreach ename (mapcar (function cadr) (ssnamex ss))
Well I tried, :-o
-
Hi CAB,
In your c:TxtC, I found it interesting that you progressively popped the first item from the selection set
at each iteration and called (entget (ssname ss 0)))
rather than create an incrementing counter as an index into a static selectionset.
-
Thanks for noticing.
That was the deference I was trying to show from Michael's example above it.
I should have dressed it up a bit as pretty does not come naturally to me as you know.
It was an exercise in ways to iterate through a selection set and that was one of them.
As you know deleting from a selection set if you are not careful can produce unwanted results.
-
Will you used the "can't" word. he he he
Maybe I misread that, but I thought he was referring to the fact you can't do
(foreach ent ss ....)
(mapcar 'entget ss)
Thanks for helping me get my point across Jeff.
I thought I was gonna have to clarify myself.
:-)
-
In the spirit of fun ...
(defun PicksetToEnames ( ss / i result )
(if (eq 'pickset (type ss))
(repeat (setq i (sslength ss))
(setq result
(cons
(ssname ss (setq i (1- i)))
result
)
)
)
)
)
:)
That's the way I read it too Jeff, ergo ..
(foreach ename (PicksetToEnames (ssget "x"))
(foo ename)
)
Or ...
(mapcar 'foo (PicksetToEnames (ssget "x")))
:)
Michael,
This just further illustrates my point that you can't get at the entities in a 'ssget' selection set.
I just thought it was funny that LE's statement that 'repeat' seems to be forgotten by most people was responded by you with an example of a situation of where the only way to get at the data in the example was to use repeat- which was the only method of the 3 previously mentioned methods that would have worked in this occurance.
:-)
-
(setq ss (ssget))
(vlax-for
item
(vla-get-activeselectionset
(vla-get-activedocument (vlax-get-acad-object)))
(print item))
-
(vlax-for
item
(vla-get-activeselectionset
(vla-get-activedocument (vlax-get-acad-object)))
(print (entget (vlax-vla-object->ename item))))
-
(setq ss (ssget))
(vlax-for
item
(vla-get-activeselectionset
(vla-get-activedocument (vlax-get-acad-object)))
(print item))
I use the following one without declaring of ss:
(ssget)
(vlax-for
item
(vla-get-activeselectionset
(vla-get-activedocument (vlax-get-acad-object)))
(print item))
-
I use the following one without declaring of ss:
(ssget)
Yep... we don't need the ss var..... I am doing this samples on the fly [like mickey-mouse code].... :-)
Thanks.
-
Michael,
This just further illustrates my point ...
Ok Will, thanks. All our awareness are belong to us.
:)
I just thought it was funny that LE's statement that 'repeat' seems to be forgotten ...
Ok x 2. I just thought Luis was talking general diminished use of repeat, so I spewed the first example that thrust itself into my nuggin. Sorry if it was a curious example.
:oops:
-
Ok now I feel bad for carrying this out to far. :cry:
Just general observations and no hard feelings ok. :-)
-
I'd rather you speak your mind than have your contributions / thoughts stifled, so you observe away my friend, and of course, no hard feelings.
And please forgive my twisted sense of humour which manisfests itself in posts like the previous.
:)
-
:-)
-
If it doesn't matter which function to use, then I use Mapcar when I want to be cool and Foreach when not. :lol:
-
I use the following one without declaring of ss:
(ssget)
(vlax-for ...
)
Might wanna do a little more like (if (ssget)(vlax-for ... )) or check PICKFIRST for further tests and such ...
Anyway, interesting thread, folks.