Is there a common LISP function to compare the contents of two lists?
Asked Answered
S

7

12

In particular, I just want to ensure that two lists have the same elements, ignoring order

Salley answered 5/11, 2010 at 22:48 Comment(0)
F
1

According to Steele "set-difference returns a list of elements of list1 that do not appear in list2. This operation is not destructive."

So if the set-difference is empty and the lengths are the same...

http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node152.html#SECTION001950000000000000000

Forman answered 5/11, 2010 at 23:20 Comment(2)
so you would say that '(1 2 2) has the same elements as '(1 1 2) ?Saxton
Depends on what you mean by 'same elements'. I see your point, though: if I answer 'yes', than length doesn't matter. If I answer 'no', set-difference doesn't solve the problem.Forman
V
10

If order isn't important, you can use equal. For instance,

(equal (list 1 2) (list 1 2))

is true. Thus one way to do it would be to (sort) the list and then use equal. Note that sort is destructive so if order matters, you might want to copy it first.

Verile answered 5/11, 2010 at 23:7 Comment(2)
It doesn't matter whether order is important or not -- SORT may destroy (not sort in-place!) the original list, so copying is a good idea in either case.Candiecandied
If order was important, the sorting (and thus the copy) would be unnecessary; (equal X Y) would be sufficient. I think that was the point.Camerlengo
S
4
(defun same-bag-p (bag1 bag2 &key (test #'eql))
  (let ((table (make-hash-table :test test)))
    (loop for key in bag1 do (incf (gethash key table 0)))
    (loop for key in bag2 do (decf (gethash key table 0)))
    (loop for val being each hash-value of table always (= val 0))))
Sharecrop answered 6/11, 2010 at 11:43 Comment(0)
L
3

If repeating items are not important see also SET-EXCLUSIVE-OR.

Londalondon answered 5/11, 2010 at 23:19 Comment(0)
F
1

According to Steele "set-difference returns a list of elements of list1 that do not appear in list2. This operation is not destructive."

So if the set-difference is empty and the lengths are the same...

http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node152.html#SECTION001950000000000000000

Forman answered 5/11, 2010 at 23:20 Comment(2)
so you would say that '(1 2 2) has the same elements as '(1 1 2) ?Saxton
Depends on what you mean by 'same elements'. I see your point, though: if I answer 'yes', than length doesn't matter. If I answer 'no', set-difference doesn't solve the problem.Forman
I
1
(defun list= (l1 l2 &key (test #'eql))
  (loop for i in l1
     for j in l2
     always (funcall test i j)))


(list= '(1 2 "a") '(1 2 "a") :test #'equal) ;; => T
(list= '(1 2 "a") '(1 2 "a") :test #'eql) ;; => NIL
Incised answered 8/11, 2018 at 9:40 Comment(0)
A
0

Sort both lists, then compare:

(equal (sort l1 #'<) (sort l2 #'<))
Ance answered 6/11, 2010 at 21:49 Comment(2)
Not really pertinent but be careful that sort will destroy the original list, so this code looks bad as in most cases either you should make a copy beforehand with e.g. (sort (copy-list l1) #'<) or you should store the result of sort back to l1 and l2. Also this approach requires sortable elements (the hash table one doesn't).Saxton
Thanks for the heads-up. I was off in pure-function-land when I wrote this.Ance
G
-1

If the order isn't important you can use "equal-set":

(equal-sets (1 2)(1 2)) -> T

(equal-sets (1 2)(2 1)) -> T

(equal-sets (1 2 5)(1 2)) -> NIL

(equal-sets (1 2)(1 5 2)) -> NIL

Gondar answered 13/10, 2013 at 3:32 Comment(2)
I cannot find this function in the specifications. Can you link to it?Hamforrd
This is not a common lisp function, it only exists in your imagination ;-)Nelan

© 2022 - 2024 — McMap. All rights reserved.