Author Topic: map the mapcar  (Read 364 times)

0 Members and 1 Guest are viewing this topic.

Grrr1337

  • Bull Frog
  • Posts: 267
map the mapcar
« on: April 12, 2017, 08:27:50 pm »
Hi everyone,
Everytime I have to manipulate some assoc list I'm using mapcar over the assoc list's elements - so that would make 2 mapcars with 2 lambda functions.
But everytime I'm using it I'm wondering can it be achieved by passing subfunctions to other subfunctions with multiple quotes (like mapcar 'mapcar '''mapcar '''''(lambda (x) ...)) :

So is there a way to double or tripple passing mapcar with a single lambda funciton? - by stacking quotes :
Code: [Select]
; Using single lambda and multiple quoting
; is it possible to ... (mapcar 'mapcar ''mapcar '''(lambda (x) (foo x) lst))

; mapcar 'mapcar ???
(mapcar '(lambda (a) (mapcar '(lambda (b) (foo b)) a)) lst)

; mapcar 'mapcar ''mapcar ???
(mapcar
  '(lambda (a)
    (mapcar
      '(lambda (b)
        (mapcar
          '(lambda (c)
            (foo c)
          ); lambda (c)
          b
        ); mapcar
      ); lambda (b)
      a
    ); mapcar
  ); lambda (a)
  lst
); mapcar

I know how the apostrophe works - but when it comes to double or tripple apostrophing/quoting - I'm getting lost by the order of evaluations.  :thinking:

gile

  • Water Moccasin
  • Posts: 2044
  • Marseille, France
Re: map the mapcar
« Reply #1 on: April 13, 2017, 03:09:10 am »
Hi,

I'm not sure to understand what you're trying to do, but you can define some functions

Code - Auto/Visual Lisp: [Select]
  1. (defun mapcaar (fun lst)
  2.  (mapcar '(lambda (a) (mapcar fun a)) lst)
  3. )
(mapcaar 'itoa '((1 2) (3 4) (5 6) (7 8 ))) -> (("1" "2") ("3" "4") ("5" "6") ("7" "8"))

Code - Auto/Visual Lisp: [Select]
  1. (defun mapcaaar (fun lst)
  2.  (mapcar '(lambda (a) (mapcaar fun a)) lst)
  3. )
(mapcaaar 'itoa '(((1 2) (3 4)) ((5 6) (7 8 )))) -> ((("1" "2") ("3" "4")) (("5" "6") ("7" "8")))
Speaking English as a French Frog

VovKa

  • Swamp Rat
  • Posts: 726
  • Ukraine
Re: map the mapcar
« Reply #2 on: April 13, 2017, 05:50:57 am »
but when it comes to double or tripple apostrophing/quoting - I'm getting lost by the order of evaluations.  :thinking:
if quoting confuses you, just use function instead
it will also speed up you code significantly

gile

  • Water Moccasin
  • Posts: 2044
  • Marseille, France
Re: map the mapcar
« Reply #3 on: April 13, 2017, 06:29:02 am »
You cannot use:
(mapcar 'mapcar ...)
with a single argument because mapcar requires at least 2 arguments (a function and one or more list)

The function passed to mapcar as argument have to require as much arguments as the number of lists passed as arguments.
So, used with a single list as this: (mapcar 'foo lst) the foo function must work with a single argument.

To be able to use an expression of type (mapcar 'mapcar ...), you have to pass it al list of functions and a list of lists containing the functions arguments:
(mapcar 'mapcar '(itoa itoa itoa itoa) '((1 2) (3 4) (5 6) (7 9))) -> (("1" "2") ("3" "4") ("5" "6") ("7" "9"))
Speaking English as a French Frog

Grrr1337

  • Bull Frog
  • Posts: 267
Re: map the mapcar
« Reply #4 on: April 13, 2017, 06:32:36 am »
Hi,

I'm not sure to understand what you're trying to do, but you can define some functions

Thanks for the input gile, but unfortunately I'm aware of these techniques.
My question is more related about passing function to another, by using (multiple?) apostrophe/quote/function, i.e.: mapcar 'mapcar ... apply 'apply ...

if quoting confuses you, just use function instead
it will also speed up you code significantly

Thanks Vova, I didn't knew that function is faster than quoting.



Ok, let me restructure my question:
Is it possible to pass mapcar function to another mapcar function, without using:
  • More than one (lambda)
  • Subfunction (defun)
  • Recursion


Code - Auto/Visual Lisp: [Select]
  1. _$ (mapcar 'mapcar ''itoa '((1 2)(3 4)(5 6))) ; is something like this doable?
  2. (((quote 2) (quote 2)) ("3" "4")) ; <- unexpected result
  3.  
  4. _$ (mapcar 'mapcar ''(lambda (x) (itoa x)) '((1 2)(3 4)(5 6))) ; another attempt - passing single (lambda) to the second (mapcar)
  5. (((quote 2) (quote 2)) ("3" "4")) ; <- unexpected result
  6.  
  7. _$ (mapcar ''((x) (mapcar 'itoa x)) '((1 2)(3 4)(5 6))) ; this works but, (x) acts like argument for the second (mapcar)
  8. (("1" "2") ("3" "4") ("5" "6")) ; <- expected result
  9.  
  10. _$ (mapcar '(mapcar '(lambda (x) (itoa x))) '((1 2)(3 4)(5 6)))
  11. Error: too few arguments ; ofcourse errors out, because no list argument is passed to the second (mapcar)
  12. _1$
  13.  

Or maybe including the subfunctions in the list using cons :
Code - Auto/Visual Lisp: [Select]
  1. (setq L '((1 2)(3 4)(5 6)))
  2. (setq L (cons itoa L))
  3. (setq L (cons mapcar L))
  4.  

Hopefully you get the idea.

EDIT: I did not saw gile's second reply... will answer soon.

EDIT2:
Ok, now I understand (actually I'm always forgetting that second way of use of mapcar - Lee showed it to me some time ago).
So the second (not so good) approach would be:
Code - Auto/Visual Lisp: [Select]
  1. (setq L '((1 2) (3 4) (5 6) (7 9)))
  2. (setq foo 'itoa)
  3. (repeat (length L) (setq fooL (cons foo fooL)))
  4. (mapcar 'mapcar fooL L)

Thanks again, Gile! :)

« Last Edit: April 13, 2017, 07:00:26 am by Grrr1337 »

gile

  • Water Moccasin
  • Posts: 2044
  • Marseille, France
Re: map the mapcar
« Reply #5 on: April 13, 2017, 07:59:54 am »
Code - Auto/Visual Lisp: [Select]
  1. (mapcar 'mapcar ''(lambda (x) (itoa x)) '((1 2)(3 4)(5 6)))
is the same as:
Code - Auto/Visual Lisp: [Select]
  1. (mapcar 'mapcar ''itoa '((1 2)(3 4)(5 6)))
and both equal:
Code - Auto/Visual Lisp: [Select]
  1. (mapcar 'mapcar '(quote itoa) '((1 2)(3 4)(5 6)))
which evaluates like:
Code - Auto/Visual Lisp: [Select]
  1. (list (mapcar 'quote '(1 2)) (mapcar 'itoa '(3 4)))
Speaking English as a French Frog

gile

  • Water Moccasin
  • Posts: 2044
  • Marseille, France
Re: map the mapcar
« Reply #6 on: April 13, 2017, 08:11:56 am »
EDIT2:
Ok, now I understand (actually I'm always forgetting that second way of use of mapcar - Lee showed it to me some time ago).
So the second (not so good) approach would be:
Code - Auto/Visual Lisp: [Select]
  1. (setq L '((1 2) (3 4) (5 6) (7 9)))
  2. (setq foo 'itoa)
  3. (repeat (length L) (setq fooL (cons foo fooL)))
  4. (mapcar 'mapcar fooL L)

You could also write it like this:
Code - Auto/Visual Lisp: [Select]
  1. (mapcar 'mapcar (mapcar '(lambda (x) 'itoa) L) L)
But it's still more cryptic (and certainly less efficient) than the original expression:
Code - Auto/Visual Lisp: [Select]
  1. (mapcar '(lambda (x) (mapcar 'itoa x)) L)
Speaking English as a French Frog

CAB

  • Global Moderator
  • Seagull
  • Posts: 10181
Re: map the mapcar
« Reply #7 on: April 13, 2017, 10:01:36 am »
And Cryptic should to be avoided at all times.
My 2 cents.
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.

Grrr1337

  • Bull Frog
  • Posts: 267
Re: map the mapcar
« Reply #8 on: April 13, 2017, 03:12:52 pm »
You could also write it like this:
Code - Auto/Visual Lisp: [Select]
  1. (mapcar 'mapcar (mapcar '(lambda (x) 'itoa) L) L)

That was exactly what I was wondering about! :yay!:

And Cryptic should to be avoided at all times.
My 2 cents.

I try to follow Roy's advice on the KISS principle, but on the other side I'm trying to explore more things inside the lisp world.
Such info may be useful to decrypt someone else's code (to understand it).

Ofcourse the most important is to understand the code you wrote by yourself. :)

roy_043

  • Swamp Rat
  • Posts: 1419
  • BricsCAD 16
Re: map the mapcar
« Reply #9 on: April 14, 2017, 03:28:22 am »
Maybe a 'mapatom' solution is what is called for here:
Code - Auto/Visual Lisp: [Select]
  1. ; 20150802: Switched to (apply ...) to support special form.
  2. ;           See: http://www.theswamp.org/index.php?topic=49859.msg550437#msg550437
  3. ; 20130729: Improved.
  4. ; 20120125
  5. ; Modify a list by applying an expression to all nested atoms.
  6. ; Nils in the list are interpretted as empty lists and not as atoms.
  7. ; Authors: Axel Strube-Zettler (http://www.autolisp.mapcar.net/).
  8. ;          Lee Mac + irneb (http://www.theswamp.org/index.php?topic=45008.0).
  9. ; (KGA_List_MapAtom  '(lambda (elem) (if (= (type elem) 'str) (strcase elem) elem)) '("a" (1 "b") ("c" 2 ("d" (3 . "e")))))
  10. ;   => ("A" (1 "B") ("C" 2 ("D" (3 . "E"))))
  11. ; (KGA_List_MapAtom 'null '(T nil T nil))
  12. ;   => (NIL NIL NIL NIL)
  13. ; Compare:
  14. ; (mapcar 'null '(T nil T nil))
  15. ;   => (NIL T NIL T)
  16. (defun KGA_List_MapAtom (expr anyLst)
  17.  (cond
  18.    ((not anyLst) ; Required.
  19.      nil
  20.    )
  21.    ((atom anyLst)
  22.      (apply expr (list anyLst))
  23.    )
  24.    (T
  25.      (cons
  26.        (KGA_List_MapAtom expr (car anyLst))
  27.        (KGA_List_MapAtom expr (cdr anyLst))
  28.      )
  29.    )
  30.  )
  31. )

Grrr1337

  • Bull Frog
  • Posts: 267
Re: map the mapcar
« Reply #10 on: April 14, 2017, 06:45:17 am »
Maybe a 'mapatom' solution is what is called for here:

Hi Roy,
Not really.. the task is more like mapping to the "nth" level:
Code - Auto/Visual Lisp: [Select]
  1. ; Given a list:
  2. (setq Lst '((("A" "B") ("C" "D")) (("E" "F") ("G" "H"))))
  3. ; Define a function (foo):
  4. ; (foo n fun Lst)
  5. ; n - level to map
  6. ; fun - function to map
  7. ; list - to be mapped
  8.  
  9. (foo 0 fun Lst) ; would map fun to items : (("A" "B") ("C" "D")) and (("E" "F") ("G" "H"))
  10. (foo 1 fun Lst) ; would map fun to items : ("A" "B") ("C" "D") ("E" "F") and ("G" "H")
  11. (foo 2 fun Lst) ; would map fun to items : "A" "B" "C" "D" "E" "F" "G" and "H"
  12.  

This looks like a challenge. :)
Anyway the atom mapping was also discussed here.

gile

  • Water Moccasin
  • Posts: 2044
  • Marseille, France
Re: map the mapcar
« Reply #11 on: April 14, 2017, 08:10:12 am »
Maybe a 'mapatom' solution is what is called for here:

Hi Roy,
Not really.. the task is more like mapping to the "nth" level:
Code - Auto/Visual Lisp: [Select]
  1. ; Given a list:
  2. (setq Lst '((("A" "B") ("C" "D")) (("E" "F") ("G" "H"))))
  3. ; Define a function (foo):
  4. ; (foo n fun Lst)
  5. ; n - level to map
  6. ; fun - function to map
  7. ; list - to be mapped
  8.  
  9. (foo 0 fun Lst) ; would map fun to items : (("A" "B") ("C" "D")) and (("E" "F") ("G" "H"))
  10. (foo 1 fun Lst) ; would map fun to items : ("A" "B") ("C" "D") ("E" "F") and ("G" "H")
  11. (foo 2 fun Lst) ; would map fun to items : "A" "B" "C" "D" "E" "F" "G" and "H"
  12.  

This looks like a challenge. :)
Anyway the atom mapping was also discussed here.

Just have a look at my first reply, I tried to make the function name self explanatory):
(foo 0 fun lst) => (mapcar fun lst) i.e. map the car level
(foo 1 fun lst) => (mapcaar fun lst) i.e. map the caar level
(foo 2 fun lst) => (mapcaaar fun lst) i.e. map the caaar level
Speaking English as a French Frog

Lee Mac

  • Seagull
  • Posts: 11626
  • AutoCAD 2015 Windows 7 London, England
Re: map the mapcar
« Reply #12 on: April 14, 2017, 09:28:24 am »
Maybe this?

Code - Auto/Visual Lisp: [Select]
  1. (defun mapncar ( n f l )
  2.    (if (< 0 n)
  3.        (mapcar '(lambda ( x ) (mapncar (1- n) f x)) l)
  4.        (mapcar 'f l)
  5.    )
  6. )
Code - Auto/Visual Lisp: [Select]
  1. _$ (setq Lst '((("A" "B") ("C" "D")) (("E" "F") ("G" "H"))))
  2. ((("A" "B") ("C" "D")) (("E" "F") ("G" "H")))
  3.  
  4. _$ (mapncar 2 (lambda ( x ) (strcase x t)) lst)
  5. ((("a" "b") ("c" "d")) (("e" "f") ("g" "h")))

gile

  • Water Moccasin
  • Posts: 2044
  • Marseille, France
Re: map the mapcar
« Reply #13 on: April 14, 2017, 09:41:22 am »
From reply #4
Ok, let me restructure my question:
Is it possible to pass mapcar function to another mapcar function, without using:
  • More than one (lambda)
  • Subfunction (defun)
  • Recursion
Speaking English as a French Frog

Grrr1337

  • Bull Frog
  • Posts: 267
Re: map the mapcar
« Reply #14 on: April 14, 2017, 10:18:37 am »

Just have a look at my first reply, I tried to make the function name self explanatory):
(foo 0 fun lst) => (mapcar fun lst) i.e. map the car level
(foo 1 fun lst) => (mapcaar fun lst) i.e. map the caar level
(foo 2 fun lst) => (mapcaaar fun lst) i.e. map the caaar level

Ah, sorry gile
I did not pay enough attention: didn't notice that mapcaaar uses mapcaar instead of mapcaaaar (for some kind of recursion).
So I thought that these would map to the caar level or to the atoms.

Still kinda sucks to define few subfunctions to reach the "nth" level.


Sorry, I started to ask for two things at the same time (greedy am I) :

- First one was is it possible / or how could you map mapcar to another, I've got the answer from gile:
You could also write it like this:
Code - Auto/Visual Lisp: [Select]
  1. (mapcar 'mapcar (mapcar '(lambda (x) 'itoa) L) L)

- Second was to map to the items on the nth level (tried to answer to Roy's suggestion, that the intention wasn't to map to the atoms).
I was thinking to start another thread about that, since I didn't expected that it could be an easy task.
However Lee Mac proved me wrong (atleast for him I think it was easy to write this one) :

Code - Auto/Visual Lisp: [Select]
  1. (defun mapncar ( n f l )
  2.  (if (< 0 n)
  3.    (mapcar '(lambda ( x ) (mapncar (1- n) f x)) l)
  4.    (mapcar 'f l)
  5.  )
  6. )
  7.  
  8. _$ (setq Lst '((("A" "B") ("C" "D")) (("E" "F") ("G" "H"))))
  9. ((("A" "B") ("C" "D")) (("E" "F") ("G" "H")))
  10.  
  11. _$ (mapncar 0 (lambda (x) (reverse x)) Lst) ; map to: (("A" "B") ("C" "D")) and (("E" "F") ("G" "H"))
  12. ((("C" "D") ("A" "B")) (("G" "H") ("E" "F")))
  13. _$ (mapncar 1 (lambda (x) (apply 'strcat x)) Lst) ; map to: ("A" "B") ("C" "D") ("E" "F") and ("G" "H")
  14. (("AB" "CD") ("EF" "GH"))
  15. _$ (mapncar 2 (lambda ( x ) (strcase x t)) lst) ; map to the atoms: "A" "B" "C" "D" "E" "F" "G" and "H"
  16. ((("a" "b") ("c" "d")) (("e" "f") ("g" "h")))
  17. _$  

Lee you deserve that list manipulator alias! :D

Lee Mac

  • Seagull
  • Posts: 11626
  • AutoCAD 2015 Windows 7 London, England
Re: map the mapcar
« Reply #15 on: April 14, 2017, 10:31:47 am »
Thanks Grrr.

Note that: (mapncar 0 (lambda (x) (reverse x)) Lst) can become: (mapncar 0 reverse lst)

Grrr1337

  • Bull Frog
  • Posts: 267
Re: map the mapcar
« Reply #16 on: April 14, 2017, 11:04:04 am »

Note that: (mapncar 0 (lambda (x) (reverse x)) Lst) can become: (mapncar 0 reverse lst)

Ah, ofcourse! Well.. the point is to have fun manipulating assoc/nested assoc lists. :)

gile

  • Water Moccasin
  • Posts: 2044
  • Marseille, France
Re: map the mapcar
« Reply #17 on: April 14, 2017, 11:04:17 am »
Thanks Grrr.

Note that: (mapncar 0 (lambda (x) (reverse x)) Lst) can become: (mapncar 0 reverse lst)

Or simply: (mapcar 'reverse lst)

Lee, is there any reason you prefer use non-quoted function as argument in higher order functions? What's wrong with built in AutoLISP functions standard quoted ones?
Speaking English as a French Frog

Lee Mac

  • Seagull
  • Posts: 11626
  • AutoCAD 2015 Windows 7 London, England
Re: map the mapcar
« Reply #18 on: April 14, 2017, 11:12:36 am »
Lee, is there any reason you prefer use non-quoted function as argument in higher order functions? What's wrong with built in AutoLISP functions standard quoted ones?

No particular reason in this case, I simply overlooked it - but I agree that the function may be better written:
Code - Auto/Visual Lisp: [Select]
  1. (defun mapncar ( n f l )
  2.    (if (< 0 n)
  3.        (mapcar '(lambda ( x ) (mapncar (1- n) f x)) l)
  4.        (mapcar f l)
  5.    )
  6. )

Such that a quoted function may be supplied, consistent with standard AutoLISP functions.

Usually it becomes necessary to supply an unquoted function to avoid the use of eval or apply within the subfunction.