Author Topic: List mapping from list 1 to list 2  (Read 3289 times)

0 Members and 1 Guest are viewing this topic.

jaydee

  • Guest
List mapping from list 1 to list 2
« on: July 17, 2011, 10:59:36 AM »
Hi.
I couldn't find anything in this forum. So i would like to ask if someone could help me.
I got these 2 lists in dotted pair and hope i could explain by having the 2 list shown below
The dotted pair is the attribute TAG and their VALUE.
The length of the 2 lists varies, one could be longer then the other or the same.
and the TAG name not in any particular order.
What I want to achieve is to map the VALUE of list 2 to list 1 only if the TAG is the same.

list 1
(("TAGY" . "333") ("TAGX" . "") ("TAGZ" . "123") ("TAG100" . "ABC") ("TAGA" . "") ("TAGB" . "456"))

list 2
(("TAG1" . "AAA") ("TAG2" . "BBB") ("TAG3" . "CCC") ("TAGX" . "DDD") ("TAGY" . "EEE") ("TAGZ" . "FFF") ("TAG11" . "GGG") ("TAG22" . "HHH"))

LIST 1 Result after mapping list 2 to list 1
(("TAGY" . "EEE") ("TAGX" . "DDD") ("TAGZ" . "FFF") ("TAG100" . "ABC") ("TAGA" . "") ("TAGB" . "456"))

Thankyou

Lee Mac

  • Seagull
  • Posts: 12922
  • London, England
Re: List mapping from list 1 to list 2
« Reply #1 on: July 17, 2011, 11:06:06 AM »
Maybe:

Code: [Select]
(defun foo ( a b )
  (mapcar '(lambda ( x ) (cond ((assoc (car x) b)) (x))) a)
)

Code: [Select]
(foo
 '(("TAGY" . "333") ("TAGX" . "") ("TAGZ" . "123") ("TAG100" . "ABC") ("TAGA" . "") ("TAGB" . "456"))
 '(("TAG1" . "AAA") ("TAG2" . "BBB") ("TAG3" . "CCC") ("TAGX" . "DDD") ("TAGY" . "EEE") ("TAGZ" . "FFF") ("TAG11" . "GGG") ("TAG22" . "HHH"))
)

==>  (("TAGY" . "EEE") ("TAGX" . "DDD") ("TAGZ" . "FFF") ("TAG100" . "ABC") ("TAGA" . "") ("TAGB" . "456"))
« Last Edit: July 17, 2011, 12:39:22 PM by Lee Mac »

Coder

  • Swamp Rat
  • Posts: 827
Re: List mapping from list 1 to list 2
« Reply #2 on: July 17, 2011, 12:37:54 PM »
That's work perfect Lee .

You have one extra paren at the end of your testing the two lists.

Regards

Lee Mac

  • Seagull
  • Posts: 12922
  • London, England
Re: List mapping from list 1 to list 2
« Reply #3 on: July 17, 2011, 12:39:40 PM »
That's work perfect Lee .

You have one extra paren at the end of your testing the two lists.

Thanks, fixed!  :-)

jaydee

  • Guest
Re: List mapping from list 1 to list 2
« Reply #4 on: July 17, 2011, 07:19:29 PM »
Thanks agian Lee
You're the man who come to rescue.

Another question. I dont need it yet, but i think it might be usefull in future.
Is it easy to mod the (foo) function to only transfer the NON NULL VALUE ie if the value is "" then ignore

ie
list1
'(("TAG1" . "AAA") )
list2
'(("TAG1" . "") )

list1 result
'(("TAG1" . "AAA") )

Sorry about this, I should have think it throught before asking questions.
I just remember. vl-remove NULL values from list 2 prior to applying (foo) function to lists.

Thankyou
« Last Edit: July 17, 2011, 08:28:23 PM by jaydee »

ronjonp

  • Needs a day job
  • Posts: 7531
Re: List mapping from list 1 to list 2
« Reply #5 on: July 18, 2011, 11:11:32 AM »
Look into the vl-remove-if function:

Code: [Select]
  (vl-remove-if
    '(lambda (x) (= (cdr x) ""))
    '(("TAGY" . "EEE")
      ("TAGX" . "DDD")
      ("TAGZ" . "FFF")
      ("TAG100" . "ABC")
      ("TAGA" . "")
      ("TAGB" . "456")
     )
  )

Make sense?

Windows 11 x64 - AutoCAD /C3D 2023

Custom Build PC

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: List mapping from list 1 to list 2
« Reply #6 on: July 18, 2011, 12:01:47 PM »
Maybe this?
Code: [Select]
(defun foo ( a b / lst)
  (mapcar '(lambda ( x / tmp )
             (setq tmp (assoc (car x) b))
             (cond
               ((and (null tmp) (/= (cdr x) ""))(setq lst (cons x lst))) ; not found in list b & /= ""
               ((and tmp (/= (cdr tmp) "")) (setq lst (cons tmp lst)))   ; found and not equal to ""
             )
           ) a)
  (reverse lst)
)
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.

Stefan

  • Bull Frog
  • Posts: 319
  • The most I miss IRL is the Undo button
Re: List mapping from list 1 to list 2
« Reply #7 on: July 18, 2011, 02:14:11 PM »
... or this
Code: [Select]
(defun ph:foo (a b)
  (vl-remove-if-not '(lambda (x) (read (cdr x)))
    (foreach n b
      (setq a (subst n (assoc (car n) a) a))
      )
    )
  )

JohnK

  • Administrator
  • Seagull
  • Posts: 10655
Re: List mapping from list 1 to list 2
« Reply #8 on: July 18, 2011, 02:23:22 PM »
I remembered seeing a very cool discussion on something like this from the Newsgroups: autodesk.autocad.customization.  Doug Broad, and Vladimir Nesterovsky created this cool "collect" procedure. ...I searched and searched through what i had left after my HD crash and i did find it but it wasn't exactly related but i modified what was there to work in this situation and this is what i came up with.

I severely crippled Vladimir's procedures functionality for this post but i wanted to post it anyway because `collect' was such a big concept piece it deserves to be studied (i will post the orig snipped discussion i had).

Code: [Select]
(setq vals '(("TAG1" . "AAA") ("TAG2" . "BBB") ("TAG3" . "CCC") ("TAGX" . "DDD") ("TAGY" . "EEE") ("TAGZ" . "FFF") ("TAG11" . "GGG") ("TAG22" . "HHH")))

(defun collect  (vals key val init-val / out a n)
  (setq out init-val)
  (foreach n vals
    (if (setq a (assoc (key n) out))
      (setq out (subst (cons (key n) (val n))
                       a out))))
  out)

(collect vals car cdr '(("TAGY" . "333") ("TAGX" . "") ("TAGZ" . "123") ("TAG100" . "ABC") ("TAGA" . "") ("TAGB" . "456")))

> (("TAGY" . "EEE") ("TAGX" . "DDD") ("TAGZ" . "FFF") ("TAG100" . "ABC") ("TAGA" . "") ("TAGB" . "456"))



Orig:
Quote
From: Nesterovsky, Vladimir <vnestr@netvision.net.il>
Subject: Re:
Newsgroups: autodesk.autocad.customization
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
Message-Id: <1115258@discussion.autodesk.com>
References: <1115257@discussion.autodesk.com>
Date: Wed, 14 Nov 2001 20:40:36 +0000

Doug Broad <dbroad@nash.cc.nc.us> wrote in message
news:388922990B12E288D8AEEA8B193C7555@in.WebX.maYIadrTaRb...
> [.....]
> ;;Examples: (collect vals car cadr +) or (collect vals car cadr list)

Now _that's_ functional programming thinking! :-)
Very, very interesting!

I took a liberty to change your code a little. The whole idea of
collecting is not to build the intermediary list, but rather apply
the result-building function while collecting, thus maintaining
the current result all the time.

That means we have to supply a function that will took two
arguments -- the interim result and the newly found value.
That also means that we have to have one more argument --
the initial value to be used on first call:

(setq vals '(("25x19" 1500)("50x19" 2500) ("25x19" 1000)
      ("6x19" 750)("50x19" 3000)("25x19" 1000)("25x19" 2000)))

(defun collect  (vals key val add init-val / out a n)
  (foreach n  vals
    (if (setq a (assoc (key n) out))
      (setq out (subst (cons (key n)
                             (add (val n) (cdr a)))
                       a out))
      (setq out (cons (cons (key n)
                            (add (val n) init-val))
                      out))))
  out)

; Examples:
;  (collect vals car cadr + 0)
;  (collect vals car cadr cons nil)

The extra init-val argument is here because of language limitations.
We should've been able to define functions capable of taking
variable number of arguments and acting accordingly, for instance,

(+ 1 2) =3D> 3
(+ 1 0) =3D> 1
(+ )  =3D> 0

so we would have defined new construct-list function so that

(conlst 1 '(2)) =3D> (1 2)
(conlst 1 '()) =3D> (1)
(conlst ) =3D> ()

Then we could drop the init-val argument and just use (add) call
with no arguments instead to produce the function's "implied" value
on first-call. I think I saw something about these "implied" values
in SICP but dont recall exactly. I think they used different name for
this concept there. Anyway...


Enjoy, :-)


P.S. By the same token (* 1 2 3) =3D=3D (* 2 3) so (* ) should return 1.
Alisp mistakenly returns 0.
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

ronjonp

  • Needs a day job
  • Posts: 7531
Re: List mapping from list 1 to list 2
« Reply #9 on: July 18, 2011, 03:30:23 PM »
... or this
Code: [Select]
(defun ph:foo (a b)
  (vl-remove-if-not '(lambda (x) (read (cdr x)))
    (foreach n b
      (setq a (subst n (assoc (car n) a) a))
      )
    )
  )

I like  8-) good solution!

Windows 11 x64 - AutoCAD /C3D 2023

Custom Build PC

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: List mapping from list 1 to list 2
« Reply #10 on: July 18, 2011, 03:59:26 PM »
One more variant from Lee's.
I like the read test though 8-)
Code: [Select]
(defun foo ( a b )
  (vl-remove-if '(lambda(x) (=(cdr x)""))
    (mapcar '(lambda ( x ) (cond ((assoc (car x) b)) (x))) a)
  )
)
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.

Stefan

  • Bull Frog
  • Posts: 319
  • The most I miss IRL is the Undo button
Re: List mapping from list 1 to list 2
« Reply #11 on: July 18, 2011, 05:44:35 PM »
A new one, faster than previously... (vl-remove and (read (cdr are not such a good (i.e. fast) idea
Code: [Select]
(defun ph:foo (a b / e lst)
  (foreach n a
    (or
      (and
(setq e (assoc (car n) b))
(/= (cdr e) "") ;prevents replacing a filled item with an empty one
(setq lst (cons e lst))
)
      (= (cdr n) "") ; remove this if an empty item from list1 is OK
      (setq lst (cons n lst))
      )
    )
  (reverse lst)
  )

jaydee

  • Guest
Re: List mapping from list 1 to list 2
« Reply #12 on: July 18, 2011, 08:28:10 PM »
Wow, theres so many ways of getting the same results.
Thankyou verymuch everyone.
You guys actually done more than what i asked for.

Initially i throught this is not right, my list (list 1) result are alot shorter, and after a closer look, you guys are right.
if list1 and list2 cantain the same TAG and both having a NULL values then its true both can be removed from listing.

Thankyou



Lee Mac

  • Seagull
  • Posts: 12922
  • London, England
Re: List mapping from list 1 to list 2
« Reply #13 on: July 19, 2011, 10:35:38 AM »
One more variant:

Code: [Select]
(defun foo ( a b )
  (apply 'append
    (mapcar
      (function
        (lambda ( x )
          (if (/= "" (cdr (setq x (cond ((assoc (car x) b)) (x))))) (list x))
        )
      )
      a
    )
  )
)