假设我有两个相同但序列不同的lisp列表:'(A B C)
和“(C B A)
。
如何检查它们是否相同(在元素相同的意义上)?
CL-USER> (equal '(a b c) '(c b a))
NIL
答案 0 :(得分:7)
像这样:
(not (set-exclusive-or '(a b c) '(c b a)))
如果两组相等则返回T
,否则返回NIL。
[编辑]如果它们不是真正的套装,那么你可以使用它:
(not (set-exclusive-or
(remove-duplicates '(a b c))
(remove-duplicates '(c b a))))
答案 1 :(得分:3)
如果列表不是集合并且重复的项目很重要,可以使用如下函数:
(defun same-elements-p (a b)
(loop (when (and (null a) (null b))
(return t))
(when (or (null a) (null b))
(return nil))
(setf b (remove (pop a) b :count 1))))
如果两个列表都是空的,则它们是相同的。我们从另一个列表中删除一个列表中的所有项目,看看会发生什么。请注意:count 1
的{{1}}参数。它确保只删除一个项目。
答案 2 :(得分:1)
我们可以定义与EQUAL和EQUALP类似的函数perm-equal
和perm-equalp
,除非参数是列表,那么它们的排列无关紧要。列表(1 1 2 3)
为perm-equal
至(2 1 3 1)
,但不包括(2 3 1)
。
该实现通过排序将值标准化为规范排列来工作。这带来了需要进行不平等比较的丑恶幽灵。但是,我们可以通过提供适用于数字,符号和字符串的预定义隐藏它来隐藏它。 (为什么sort
函数没有这样做,eql
默认为:key
参数的方式?)
(defun less (a b)
(if (realp a)
(< a b)
(string< a b)))
(defun lessp (a b)
(if (realp a)
(< a b)
(string-lessp a b)))
(defun perm-equal (a b &optional (pred #'less))
(if (or (atom a) (atom b))
(equal a b)
(let ((as (sort (copy-list a) pred))
(bs (sort (copy-list b) pred)))
(equal as bs))))
(defun perm-equalp (a b &optional (pred #'lessp))
(if (or (atom a) (atom b))
(equalp a b)
(let ((as (sort (copy-list a) pred))
(bs (sort (copy-list b) pred)))
(equalp as bs))))
注意:
equalp
比较向量,perm-equalp
也不会将其置换 - 压缩逻辑扩展到向量。realp
用于测试数字,因为复数满足numberp
,但无法与<
进行比较。答案 3 :(得分:1)
非集合的简单答案是对两个列表进行排序。 CL的默认排序具有破坏性,因此如果您想在之后保留它们,则需要副本。
(defun sorted (a-list predicate)
(sort (copy-list a-list) predicate))
(defun same-list-p (list-a list-b predicate)
(equalp (sorted list-a predicate) (sorted list-b predicate)))
它没有最佳性能,但简单而实用。
答案 4 :(得分:0)
这对我来说就像O(n)变体:
(defun equal-elementwise (a b &key (test #'eq))
(loop with hash = (make-hash-table :test test)
for i on a for j on b do
(let ((i (car i)) (j (car j)))
(unless (funcall test i j)
(setf (gethash i hash) (1+ (gethash i hash 0))
(gethash j hash) (1- (gethash j hash 0)))))
finally (return
(unless (or (cdr i) (cdr j))
(loop for value being the hash-value of hash do
(unless (zerop value) (return))
finally (return t))))))
但是,这在短名单上效率不高。