Sorting 在公共lisp中按两个属性排序

Sorting 在公共lisp中按两个属性排序,sorting,lisp,common-lisp,Sorting,Lisp,Common Lisp,我需要在common lisp中按两个属性排序的帮助 假设我有一张清单: 1 x2 y1 x2 x3 y2 y我正在尝试按字符串和整数进行排序。 所以结果是1 x1 x2 x2 y2 y3 y 目前,我可以按变量或数字排序,但不能同时按变量和数字排序。如果输入2 x1 x1 y2 x1 y,则返回1 Y1 y2 x1 X2 X,而不是1 Y1 Y1 X2 X 我使用的代码是: (defun get-number (term) (destructuring-bind (number varia

我需要在common lisp中按两个属性排序的帮助

假设我有一张清单: 1 x2 y1 x2 x3 y2 y我正在尝试按字符串和整数进行排序。 所以结果是1 x1 x2 x2 y2 y3 y

目前,我可以按变量或数字排序,但不能同时按变量和数字排序。如果输入2 x1 x1 y2 x1 y,则返回1 Y1 y2 x1 X2 X,而不是1 Y1 Y1 X2 X

我使用的代码是:

(defun get-number (term)
  (destructuring-bind (number variable) term
    (declare (ignore variable))
    number))

(defun get-variable (term)
  (destructuring-bind (number variable) term
    (declare (ignore number))
    variable))

(defun varsort (p1)
    (sort (copy-list p1) 'string> :key 'get-variable))
我的问题是,我如何才能按术语作为一个整体进行排序,使1 X而不仅仅是1或X。

两个选项:

根据get编号对varsort的结果进行稳定排序 定义要在排序中使用的自定义比较函数:

是编写通用比较函数的好方法。由于您正在操作元组,因此可以更具体地编写以下内容:

(defun tuple-compare (comparison-functions)
  (lambda (left right)
    (loop for fn in comparison-functions
          for x in left
          for y in right
          thereis (funcall fn x y)
          until (funcall fn y x))))
例如:

(sort (copy-seq #((1 2) (2 3) (1 3) (2 1)))
      (tuple-compare (list #'< #'<)))

=> #((1 2) (1 3) (2 1) (2 3))
两种选择:

根据get编号对varsort的结果进行稳定排序 定义要在排序中使用的自定义比较函数:

是编写通用比较函数的好方法。由于您正在操作元组,因此可以更具体地编写以下内容:

(defun tuple-compare (comparison-functions)
  (lambda (left right)
    (loop for fn in comparison-functions
          for x in left
          for y in right
          thereis (funcall fn x y)
          until (funcall fn y x))))
例如:

(sort (copy-seq #((1 2) (2 3) (1 3) (2 1)))
      (tuple-compare (list #'< #'<)))

=> #((1 2) (1 3) (2 1) (2 3))

可以通过组合谓词来实现这一点。如果您有一个可以比较变量的谓词和一个可以比较系数的谓词,那么您可以轻松地创建一个新的谓词来检查一个谓词,如果第一个谓词提供了一个确定的答案,则返回一个确定的答案,如果第二个谓词没有提供答案,则遵从第二个谓词。这也可用于其他应用程序:

(defun and-then (original-predicate next-predicate)
  "Returns a new predicate constructed from ORIGINAL-PREDICATE and
NEXT-PREDICATE.  The new predicate compares two elements, x and y, by
checking first with ORIGINAL-PREDICATE.  If x is less than y under
ORIGINAL-PREDICATE, then the new predicate returns true.  If y is less
than x under ORIGINAL-PREDICATE, then the new predicate returns false.
Otherwise, the new predicate compares x and y using NEXT-PREDICATE."
  (lambda (x y)
    (cond
      ((funcall original-predicate x y) t)
      ((funcall original-predicate y x) nil)
      (t (funcall next-predicate x y)))))

然后很容易调用,然后“variable<”coefficient,您可以通过组合谓词来实现这一点。如果您有一个可以比较变量的谓词和一个可以比较系数的谓词,那么您可以轻松地创建一个新的谓词来检查一个谓词,如果第一个谓词提供了一个确定的答案,则返回一个确定的答案,如果第二个谓词没有提供答案,则遵从第二个谓词。这也可用于其他应用程序:

(defun and-then (original-predicate next-predicate)
  "Returns a new predicate constructed from ORIGINAL-PREDICATE and
NEXT-PREDICATE.  The new predicate compares two elements, x and y, by
checking first with ORIGINAL-PREDICATE.  If x is less than y under
ORIGINAL-PREDICATE, then the new predicate returns true.  If y is less
than x under ORIGINAL-PREDICATE, then the new predicate returns false.
Otherwise, the new predicate compares x and y using NEXT-PREDICATE."
  (lambda (x y)
    (cond
      ((funcall original-predicate x y) t)
      ((funcall original-predicate y x) nil)
      (t (funcall next-predicate x y)))))

然后很容易调用,然后调用“variable<”coefficient当你说另一个键时,你是指get number吗?当你说另一个键时,你是指get number吗?堆栈溢出的贡献是根据允许复制和复制的条款许可的。复制和重用东西是可以的,但属性是必需的。虽然您已经更改了函数的实际名称,但似乎您的访问器get number和get variable以及varsort的主体都是从中复制的。可以这样复制它们,但您可能应该在这里包含一个指向您前面问题的链接。对堆栈溢出的贡献是根据允许复制和复制的条款授权的。复制和重用东西是可以的,但属性是必需的。虽然您已经更改了函数的实际名称,但似乎您的访问器get number和get variable以及varsort的主体都是从中复制的。可以这样复制它们,但是您可能应该在这里包含一个指向您先前问题的链接。谢谢!我在Emacs中使用ace窗口来切换窗口,但我希望窗口按框架顶部、左侧和在一个框架内编号,就像你在书中读到的那样,从顶部开始,从左到右编号,然后向下编号,从左到右编号,等等。然后与你的和进行比较,我添加了defun make composited comparators l seq减少lambda old new,然后通过“(defun term-coefficient (term) (first term)) (defun coefficient< (term1 term2) (< (term-coefficient term1) (term-coefficient term2))) (defun term-variable (term) (second term)) (defun variable< (term1 term2) (string< (term-variable term1) (term-variable term2)))
(defparameter *sample*
  '((1 x)(2 y)(1 x)(2 x)(3 y)(2 y)))
CL-USER> (sort (copy-list *sample*) 'coefficient<)
((1 X) (1 X) (2 Y) (2 X) (2 Y) (3 Y))

CL-USER> (sort (copy-list *sample*) 'variable<)
((1 X) (1 X) (2 X) (2 Y) (3 Y) (2 Y))

CL-USER> (sort (copy-list *sample*) (and-then 'variable< 'coefficient<))
((1 X) (1 X) (2 X) (2 Y) (2 Y) (3 Y))
(defun compare-by (predicate key)
  "Returns a function that uses PREDICATE to compare values extracted
by KEY from the objects to compare."
  (lambda (x y)
    (funcall predicate
             (funcall key x)
             (funcall key y))))
(defun coefficient< (term1 term2)
  (funcall (compare-by '< 'term-coefficient) term1 term2))

(defun variable< (term1 term2)
  (funcall (compare-by 'string< 'term-variable) term1 term2))
(defun varsort (p1)
  (sort (copy-list p1)
        (and-then (compare-by '<       'term-coefficient)
                  (compare-by 'string< 'term-variable))))