比较多个元素

时间:2014-12-05 15:45:34

标签: lisp common-lisp

所以我想比较来自四个不同列表的四个不同元素。类似于下面的例子,问题是相等应该只接收2个参数,是否有任何函数可以比较2个以上的元素?

(equal (nth 0 '(1 2 3)) (nth 0 '(1 2 3)) (nth 0 '(1 2 3)) (nth 0 '(1 2 3)))

2 个答案:

答案 0 :(得分:4)

例如,您可以将每个元素与第一个元素进行比较,类似于:

(defun meql (func &rest args)
  (every (lambda (arg)
           (funcall func arg (first args)))
         (rest args)))

CL-USER> (meql #'eq 'a 'a 'a) 
T
CL-USER> (meql #'eq 'a 'b 'a)
NIL
CL-USER> (meql #'equal "foo" "FOO" "foo")
NIL
CL-USER> (meql #'equalp "foo" "FOO" "foo")
T

答案 1 :(得分:4)

  

是否有任何比较2个以上元素的函数?

Common Lisp中的许多比较函数都接受两个以上的参数。例如,所有=, /=, <, >, <=, >=都接受任意数量的参数,这意味着您可以执行

(= (nth 0 '(1 2 3))
   (nth 0 '(1 2 3))
   (nth 0 '(1 2 3))
   (nth 0 '(1 2 3)))

如果您需要相等(而不是 = )的特定行为,那么您将需要coredump proposed的方法。由于相等性是可传递的,因此您可以检查每个元素是否与第一个元素相等(或者列表为空):

(defun equal* (&rest arguments)
  (or (endp arguments)
      (let ((x (first arguments)))
        (every (lambda (y)
                 (equal x y))
               (rest arguments)))))

(equal* 1 1 1 1)
;=> T

实际上,由于您可以使用空列表调用第一个休息,您甚至可以摆脱第一个案例,因为每个传递空列表时将返回true:

(defun equal* (&rest arguments &aux (x (first arguments)))
  (every (lambda (y)
           (equal x y))
         (rest arguments)))

之后,由于这可能是一种常见的模式,您可以定义一个宏来为您定义这些模式:

(defmacro def-n-ary-equality (name predicate &rest args)
  (let ((arguments (gensym (string '#:arguments-)))
        (x (gensym (string '#:x-)))
        (y (gensym (string '#:y-))))
    `(defun ,name (&rest ,arguments &aux (,x (first ,arguments)))
       (every (lambda (y)
                (,predicate ,x ,y ,@args))
              (rest ,arguments)))))

(def-n-ary-equality equal* equal)
; ==
(DEFUN EQUAL* (&REST #:ARGUMENTS-1005 &AUX (#:X-1006 (FIRST #:ARGUMENTS-1005)))
  (EVERY (LAMBDA (Y)
           (EQUAL #:X-1006 #:Y-1007))
         (REST #:ARGUMENTS-1005)))