Author Topic: Trying to Understand Mapcar/Lambda for (if (= x "Y"))  (Read 3472 times)

0 Members and 1 Guest are viewing this topic.

Bill Tillman

  • Guest
Trying to Understand Mapcar/Lambda for (if (= x "Y"))
« on: June 19, 2013, 09:03:40 AM »
I have an exercise this morning I'm working on and thought why not make use of the time to learn more about mapcar/lambda.

I have four variables:

Quote
front   back   rside  lside

If any of these variables contains the value of "Y" I want to take some action. I've been doing this in the past:

Code: [Select]
(if (or (= front "Y") (= back "Y") (= rside "Y") (= lside "Y")) (setq a "Y"))
All the mapcar examples I've searched through so far show how to add 1, subtract 2, strcase, etc... How would one run this process through mapcar/lambda to achieve the same results?

ronjonp

  • Needs a day job
  • Posts: 7529
Re: Trying to Understand Mapcar/Lambda for (if (= x "Y"))
« Reply #1 on: June 19, 2013, 09:09:24 AM »
You could use vl-some like so:


Code: [Select]
(and (vl-some '(lambda (x) (= x "Y")) (list front back rside lside)) (setq a "Y"))

Windows 11 x64 - AutoCAD /C3D 2023

Custom Build PC

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Trying to Understand Mapcar/Lambda for (if (= x "Y"))
« Reply #2 on: June 19, 2013, 09:20:03 AM »
Ronjonp's is definitely the way to go if you have to use lambda.

If you want to use mapcar as well, you could use the following
Code - Auto/Visual Lisp: [Select]
  1. (if (apply 'or (mapcar '(lambda (x) (= x "Y")) (list front back rside lside)))
  2.  ;;;;
  3. )
Note though, that I'd not advise this, as it checks through each and every variable even if front is already = "Y". Ronjonp's code will work the same way a normal or would - i.e. only evaluate until a T is returned.

Another alternative would be to use vl-position or member:
Code - Auto/Visual Lisp: [Select]
  1. ;; Using vl-position
  2. (if (vl-position "Y" (list front back rside lside))
  3.   ;;;;
  4. )
  5.  
  6. ;; Or using member
  7. (if (member "Y" (list front back rside lside))
  8.   ;;;;
  9. )
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

BlackBox

  • King Gator
  • Posts: 3770
Re: Trying to Understand Mapcar/Lambda for (if (= x "Y"))
« Reply #4 on: June 19, 2013, 11:22:22 AM »
If any of these variables contains the value of "Y" I want to take some action. I've been doing this in the past:

Code: [Select]
(if (or (= front "Y") (= back "Y") (= rside "Y") (= lside "Y")) (setq a "Y"))
... How would one run this process through mapcar/lambda to achieve the same results?

From a duplicate thread here:

Quote from: BlackBox
Consider:
Code: [Select]
(setq a
       (car
         (vl-remove-if-not
           (function (lambda (x) (= "Y" x)))
           (list front back rside lside)
         )
       )
)
"How we think determines what we do, and what we do determines what we get."

ronjonp

  • Needs a day job
  • Posts: 7529
Re: Trying to Understand Mapcar/Lambda for (if (= x "Y"))
« Reply #5 on: June 19, 2013, 11:45:56 AM »
Here's some more benchmarks :).


Quote
;; Y at front of list
    _FOO6.....1453 / 1.05 <fastest>
    _FOO3.....1469 / 1.04
    _FOO5.....1469 / 1.04
    _FOO2.....1484 / 1.03
    _FOO4.....1484 / 1.03
    _FOO1.....1531 / 1.00 <slowest>
;; Y at end of list
    _FOO5.....1141 / 1.34 <fastest>
    _FOO4.....1203 / 1.27
    _FOO6.....1219 / 1.26
    _FOO3.....1297 / 1.18
    _FOO1.....1500 / 1.02
    _FOO2.....1531 / 1.00 <slowest>


Code: [Select]
(defun _foo1 ()
  (vl-some (function (lambda (v)
             (if (eq (eval v) "Y")
          "Y"
             )
           )
      )
      (list front back rside lside)
  )
)

(defun _foo2 ()
  (car (vl-remove-if-not (function (lambda (x) (eq x "Y"))) (list front back rside lside)))
)
(defun _foo3 nil (vl-some (function (lambda (x) (eq x "Y"))) (list front back rside lside)))

(defun _foo4 nil (vl-position "Y" (list front back rside lside)))

(defun _foo5 nil (member "Y" (list front back rside lside)))

(defun _foo6 nil (or (= front "Y") (= back "Y") (= rside "Y") (= lside "Y")))

(defun _foo7 nil (apply 'or (mapcar '(lambda (x) (= x "Y")) (list front back rside lside))))

(benchmark '(_foo1 _foo2 _foo3 _foo4 _foo5 _foo6))

Windows 11 x64 - AutoCAD /C3D 2023

Custom Build PC

BlackBox

  • King Gator
  • Posts: 3770
Re: Trying to Understand Mapcar/Lambda for (if (= x "Y"))
« Reply #6 on: June 19, 2013, 11:56:22 AM »
Here's some more benchmarks :).

... Too bad only _foo1, and _foo2 yield the same returned value as the OP's code as requested.  :-P
"How we think determines what we do, and what we do determines what we get."

ronjonp

  • Needs a day job
  • Posts: 7529
Re: Trying to Understand Mapcar/Lambda for (if (= x "Y"))
« Reply #7 on: June 19, 2013, 12:11:11 PM »
I also missed _foo7 LOL ... Here's new numbers with all functions returning "Y" :P


Quote
;; Y at front of list


    _FOO2.....1125 / 1.03 <fastest>
    _FOO4.....1125 / 1.03
    _FOO6.....1125 / 1.03
    _FOO7.....1125 / 1.03
    _FOO5.....1140 / 1.01
    _FOO3.....1141 / 1.01
    _FOO1.....1157 / 1.00 <slowest>


;; Y at end of list


    _FOO7.....1110 / 1.04 <fastest>
    _FOO2.....1125 / 1.03
    _FOO3.....1125 / 1.03
    _FOO4.....1125 / 1.03
    _FOO5.....1125 / 1.03
    _FOO6.....1141 / 1.01
    _FOO1.....1156 / 1.00 <slowest>

Windows 11 x64 - AutoCAD /C3D 2023

Custom Build PC

BlackBox

  • King Gator
  • Posts: 3770
Re: Trying to Understand Mapcar/Lambda for (if (= x "Y"))
« Reply #8 on: June 19, 2013, 12:13:17 PM »
I also missed _foo7 LOL ... Here's new numbers with all functions returning "Y" :P



Code - Auto/Visual Lisp: [Select]
  1. ;; Y at front of list
  2.  
  3.  
  4.     _FOO2.....1125 / 1.03 <fastest>
  5.     _FOO4.....1125 / 1.03
  6.     _FOO6.....1125 / 1.03
  7.     _FOO7.....1125 / 1.03
  8.     _FOO5.....1140 / 1.01
  9.     _FOO3.....1141 / 1.01
  10.     _FOO1.....1157 / 1.00 <slowest>
  11.  
  12.  
  13. ;; Y at end of list
  14.  
  15.  
  16.     _FOO7.....1110 / 1.04 <fastest>
  17.     _FOO2.....1125 / 1.03
  18.     _FOO3.....1125 / 1.03
  19.     _FOO4.....1125 / 1.03
  20.     _FOO5.....1125 / 1.03
  21.     _FOO6.....1141 / 1.01
  22.     _FOO1.....1156 / 1.00 <slowest>


First place in round 1, Second in round 2, best overall isn't bad at all... Yay me!  :lol:
"How we think determines what we do, and what we do determines what we get."

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Trying to Understand Mapcar/Lambda for (if (= x "Y"))
« Reply #9 on: June 19, 2013, 03:03:37 PM »
A bit contrived  :-P, but a recursive member function
Code - Auto/Visual Lisp: [Select]
  1. (defun member-r (pred lst)
  2.   (cond ((eq pred (car lst)) lst)
  3.         (lst (member-r pred (cdr lst)))))
  4.  
  5. (if (member-r "Y" (list front back rside lside))
Probably not too great on speed in comparison to the others.

Anyhow, to answer the OP's "actual" question ... making the sample data to test on shows another reason to use mapcar:
Code: [Select]
_$ (mapcar 'set '(front back rside lside) '("W" "X" "Y" "Z"))
("W" "X" "Y" "Z")
_$ front
"W"
_$ back
"X"
_$ rside
"Y"
_$ lside
"Z"
That shows what's happening with mapcar. The equivalent (if not using mapcar) would have been:
Code - Auto/Visual Lisp: [Select]
  1. (list (set 'front "W")
  2.       (set 'back "X")
  3.       (set 'rside "Y")
  4.       (set 'lside "Z"))
Lambda is simply a way of defining a function direct in the position where it's called. E.g. the following is equivalent to RonJonP's code in Post #2:
Code - Auto/Visual Lisp: [Select]
  1. (defun eq-Y (x)
  2.   (= x "Y"))
  3. (and (vl-some 'eq-Y (list front back rside lside)))
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.