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é
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'~
@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.
@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.
--
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
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é
@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")
@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
Tharwat
@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")
--
@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)))
@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")
--
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é
@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.