Author Topic: mapcar or foreach  (Read 11782 times)

0 Members and 1 Guest are viewing this topic.

Mark

  • Custom Title
  • Seagull
  • Posts: 28762
mapcar or foreach
« on: November 22, 2005, 09:17:56 AM »
Can you tell me when it's appropriate to use either mapcar or foreach?
TheSwamp.org  (serving the CAD community since 2003)

LE

  • Guest
Re: mapcar or foreach
« Reply #1 on: November 22, 2005, 09:42:27 AM »
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

JohnK

  • Administrator
  • Seagull
  • Posts: 10648
Re: mapcar or foreach
« Reply #2 on: November 22, 2005, 10:00:10 AM »
^^ 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:
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: mapcar or foreach
« Reply #3 on: November 22, 2005, 10:03:59 AM »
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)


:)
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

LE

  • Guest
Re: mapcar or foreach
« Reply #4 on: November 22, 2005, 10:19:01 AM »
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.

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: mapcar or foreach
« Reply #5 on: November 22, 2005, 10:22:18 AM »
I use repeat often --

(if (setq ss (ssget))
    (repeat (setq i (sslength ss))
        (foo (ssname ss (setq i (1- i))))
    )
)
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

Joe Burke

  • Guest
Re: mapcar or foreach
« Reply #6 on: November 22, 2005, 10:27:17 AM »
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.

Mark

  • Custom Title
  • Seagull
  • Posts: 28762
Re: mapcar or foreach
« Reply #7 on: November 22, 2005, 12:46:16 PM »
How about some examples of working with an entity list?
TheSwamp.org  (serving the CAD community since 2003)

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: mapcar or foreach
« Reply #8 on: November 22, 2005, 12:48:44 PM »
Context please.

:)
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

Mark

  • Custom Title
  • Seagull
  • Posts: 28762
Re: mapcar or foreach
« Reply #9 on: November 22, 2005, 01:04:15 PM »
May not be the best example.

Code: [Select]
(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))
  )
TheSwamp.org  (serving the CAD community since 2003)

LE

  • Guest
Re: mapcar or foreach
« Reply #10 on: November 22, 2005, 01:09:22 PM »
In example change the ename's color to RED

Code: [Select]
(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))))))

Code: [Select]
(mapcar '(lambda (obj) (vla-put-color obj acRed))
(mapcar 'vlax-ename->vla-object (list ent1 ent2 ent3)))

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: mapcar or foreach
« Reply #11 on: November 22, 2005, 01:11:27 PM »
Code: [Select]
(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)
    )
)
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: mapcar or foreach
« Reply #12 on: November 22, 2005, 01:35:32 PM »
Sorry don't have time to pen something pretty but perhaps this will illuminate ...

Code: [Select]
(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)

)
« Last Edit: November 22, 2005, 01:39:39 PM by MP »
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

paulmcz

  • Bull Frog
  • Posts: 202
Re: mapcar or foreach
« Reply #13 on: November 22, 2005, 03:06:10 PM »
"foreach" can speed things up significantly. Compare these two ways of drawing an ellipse:

This one with use of "foreach"

Code: [Select]
(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:

Code: [Select]
(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")

whdjr

  • Guest
Re: mapcar or foreach
« Reply #14 on: November 22, 2005, 04:15:30 PM »
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]