Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

compare two lists

15 REPLIES 15
Reply
Message 1 of 16
andre_lag
2957 Views, 15 Replies

compare two lists

Hi,

I have two lists to compare and want the difference in an third list.

like

list1 ("A" "B" "C")

list2 ("A" "B" "C" "D" "E")

 

the differenc in list3 ("D" "E")

 

any suggestion?

Thnx

Regards

André

15 REPLIES 15
Message 2 of 16
Hallex
in reply to: andre_lag

VL-MEMBER-IF is your friend:

(setq list1 '("A" "B" "C")
      list2 '("A" "B" "C" "D" "E"))

 (if (< (length list2)(length list1))
	(progn
	  (setq swap (list list1 list2)
		lista (cadr swap)
		listb (car swap)))
   (progn
    (setq  lista list1
	   listb list2)))
(setq result (vl-member-if-not (function (lambda (a)(member a lista))) listb))

 

~'J'~

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 3 of 16
Kent1Cooper
in reply to: andre_lag


@andre_lag wrote:

....

I have two lists to compare and want the difference in an third list.

like

list1 ("A" "B" "C")

list2 ("A" "B" "C" "D" "E")

 

the differenc in list3 ("D" "E")

....


On the assumption that everything in the shorter list is in the longer list, here's another way:

 

(setq

  list1 '("A" "B" "C")
  list2 '("A" "B" "C" "D" "E"))
  listS (if (< (length list1) (length list2)) list1 list2); the Shorter list

  list3 (car (vl-remove listS (list list1 list2)))); the other one, to start

)

(foreach x listS (setq list3 (vl-remove x list3)))

 

That returns

("D" "E")

 

If both lists might contain things that are not in the other list, you would need to define what you want to do about that.  Or if the longer list might have more than one of any item that's in the shorter list, and you want only as many as are in the shorter list to be removed from the longer list, then it would need to be more sophisticated.

Kent Cooper, AIA
Message 4 of 16
martti.halminen
in reply to: andre_lag


@andre_lag wrote:

Hi,

I have two lists to compare and want the difference in an third list.

like

list1 ("A" "B" "C")

list2 ("A" "B" "C" "D" "E")

 

the differenc in list3 ("D" "E")

 


(defun set-difference (a-list b-list / res)
  ;; returns a list of all items in a-list that are not in b-list
  (foreach a a-list
    (if (not (member a b-list))
        (setq res (cons a res))))
  (reverse res))

 $ (setq list3 (set-difference list2 list1))
("D" "E")

 

 

- the name is borrowed from the corresponding Common Lisp function, though neither actually enforces the data to be a mathematical set i.e. removing duplicates.

--

Message 5 of 16
_Tharwat
in reply to: andre_lag

Another with mapcar and lambda .

 

(setq list2 '("A" "B" "C"))
(setq list1 '("A" "B" "C" "D" "E"))

(if (< (length list1) (length list2))
  (mapcar (function (lambda (x) (if (not (member x list1))(setq l (cons x l)))))
	  list2
  )
  (mapcar (function (lambda (x) (if (not (member x list2))(setq l (cons x l)))))
	  list1
  )
)
(reverse l)

 Tharwat

Message 6 of 16
andre_lag
in reply to: andre_lag

Thanks guys for your reply,

give every solution a try,

regards

André

Message 7 of 16
andre_lag
in reply to: andre_lag

I have make a mistake, because i want to no in which list(s) are the difference.

for example:

list1 ("A" "B" "C" "E")

list2 ("A" "C" "D" "F")

 

result: list1 ("B" "E") and list2 ("D" "F")

 

Please, can you modify the code a little, so that this will work?

Thnx

Regards

André  

 

 

 

 

Message 8 of 16
Kent1Cooper
in reply to: andre_lag


@andre_lag wrote:

I have make a mistake, because i want to no in which list(s) are the difference.

for example:

list1 ("A" "B" "C" "E")

list2 ("A" "C" "D" "F")

 

result: list1 ("B" "E") and list2 ("D" "F")

.... 


This does that, though I put the results into list1only and list2only variables, so as not to change the original lists:

 

(vl-load-com); if needed

(setq
  list1 '("A" "B" "C" "E")
  list2 '("A" "C" "D" "F")
  list1only list1 list2only list2 ; to start
)

(foreach x list1 (setq list2only (vl-remove x list2only)))
(foreach x list2 (setq list1only (vl-remove x list1only)))

 

Then:

Command: !list1only
("B" "E")

Command: !list2only
("D" "F")

Kent Cooper, AIA
Message 9 of 16
_Tharwat
in reply to: andre_lag


@andre_lag wrote:

I have make a mistake, because i want to no in which list(s) are the difference.

for example:

list1 ("A" "B" "C" "E")

list2 ("A" "C" "D" "F")

 

result: list1 ("B" "E") and list2 ("D" "F")

 

Please, can you modify the code a little, so that this will work?

Thnx

Regards

André  

 


My codes work for that result also as well Smiley Happy

 

Tharwat

Message 10 of 16
martti.halminen
in reply to: andre_lag


@andre_lag wrote:

I have make a mistake, because i want to no in which list(s) are the difference.

for example:

list1 ("A" "B" "C" "E")

list2 ("A" "C" "D" "F")

 

result: list1 ("B" "E") and list2 ("D" "F")

 

Please, can you modify the code a little, so that this will work?

 

 


No need to modify anything, just call the functions accordingly:

 

$ (set-difference list1 list2)
("B" "E")
_$ (set-difference list2 list1)
("D" "F")

 

--

 

 

Message 11 of 16
andre_lag
in reply to: andre_lag

Thanks a lot, guys

 

Martti, how can i get the comparison case-insensitive?

thnx

regards,

André

Message 12 of 16
Kent1Cooper
in reply to: andre_lag


@andre_lag wrote:

.... 

Martti, how can i get the comparison case-insensitive?

....


Untested, but it should be enough to change this line:
 

(if (not (member a b-list))

 

to this:

 

(if (not (member (strcase a) (mapcar 'strcase b-list)))

Kent Cooper, AIA
Message 13 of 16


@Kent1Cooper wrote:

@andre_lag wrote:

.... 

Martti, how can i get the comparison case-insensitive?

....


Untested, but it should be enough to change this line:
 

(if (not (member a b-list))

 

to this:

 

(if (not (member (strcase a) (mapcar 'strcase b-list)))


The version suggested by Kent should work, though for huge lists the performance would be better if that mapcar call was taken outside the foreach loop.

 

Alternately, if it is acceptable that the results are upcased, you could just modify the values used to call the function:

 

_$ (setq list1 '("A" "b" "C")
      list2 '("A" "B" "c" "D" "e"))

_$ (set-difference list2 list1)
("B" "c" "D" "e")
_$ (set-difference (mapcar 'strcase list2) list1)
("B" "D" "E")

_$ (set-difference list2 (mapcar 'strcase list1))
("c" "D" "e")
_$ (set-difference (mapcar 'strcase list2) (mapcar 'strcase list1))
("D" "E")

 

--

 

 

 

 

 

Message 14 of 16
andre_lag
in reply to: andre_lag

Hi Kent,

 

Don't understand your last reply.

use your code, and want this comparison case insensitive.

list1 and list2 are my examples

 

(vl-load-com); if needed

(setq   list1 '("A" "b" "C" "d")  

list2 '("A" "B" "D" "E" "f")  

list1only list1 list2only list2 ; to start

)

(foreach x list1 (setq list2only (vl-remove x list2only)))

(foreach x list2 (setq list1only (vl-remove x list1only)))

 

the result must be:

Command: !list1only ("C")

Command: !list2only ("E" "f")

 

can you change this code?

Thnx

Regards

André

 

 

Message 15 of 16
Kent1Cooper
in reply to: andre_lag


@andre_lag wrote:

Hi Kent,

Don't understand your last reply.

....


My last reply was suggesting a change to Martti's routine, rather than to mine, to make it compare all items in their upper-case form.  That seemed a lot easier to do with his (member) approach than I thought it would be with the (foreach) approach, if you want the results to retain the upper- or lower-case condition of the items in the original lists, and you might have some of either case in either list.  But you could do this to mine:

 

(vl-load-com); if needed

(setq

  list1 '("A" "b" "C" "d")

  list2 '("A" "B" "D" "E" "f")

  list1only list1 list2only list2 ; to start

); setq

(foreach x list1

  (setq

    list2only (vl-remove (strcase x) list2only); remove upper-case equivalents

    list2only (vl-remove (strcase x T) list2only); remove lower-case equivalents

  ); setq

); foreach

(foreach x list2

  (setq

    list1only (vl-remove (strcase x) list1only)

    list1only (vl-remove (strcase x T) list1only)

  ); setq

); foreach

 

If, on the other hand, you don't mind converting both lists to all one case or the other, and losing the case distinctions, it would be a simpler adjustment to my routine:

 

...

(setq

  list1 (mapcar 'strcase '("A" "b" "C" "d"))

  list2 (mapcar 'strcase '("A" "B" "D" "E" "f"))

...

and the rest the same as it was.

Kent Cooper, AIA
Message 16 of 16
andre_lag
in reply to: andre_lag

Thanks again Kent,

 

use your last suggestion, works great

thanks a lot

regards

André

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report

”Boost