比较lisp中的两个符号列表

时间:2013-04-25 23:51:34

标签: comparison lisp common-lisp

假设我有两个相同但序列不同的lisp列表:'(A B C)和“(C B A)。 如何检查它们是否相同(在元素相同的意义上)?

CL-USER> (equal '(a b c) '(c b a))
NIL

5 个答案:

答案 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-equalperm-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))))))

但是,这在短名单上效率不高。