2017-07-24 63 views
3

我想要那种看起来像这样的列表:Lisp的排序功能键

(defvar my-list '((:x 1 :y something) (:x 5 :y something) (:x 19 :y something))) 

我试图通过:x值来排序。我是这样做的

(sort my-list #'> :key #'second) 

,但我非常喜欢使用的,而不是secondgetf功能,但我无法弄清楚如何通过:x作为参数。

从我可以收集只是#'getf回报(getf ((:x 1 :y something) '(:x 5 :y something) (:x 19 :y something)) [external]。我会如何去通过:x作为第二个参数?

我能想到的唯一方法是为getf创建一个包装函数,它仅将一个列表作为参数,并在默认情况下通过:x。但必须有更好的方法。

+3

您不需要引用引用列表中的子列表。另外,你不应该在引用(文字)列表中使用像'SORT'这样的破坏性操作。在排序之前,您可以使用“COPY-LIST”(或“COPY-TREE”)复制列表。对于问题本身,制作包装函数是通常的解决方案。这通常被称为咖喱。 [亚历山大](https://common-lisp.net/project/alexandria/)库具有函数'CURRY'和'RCURRY'。 – jkiiski

+0

@jkiiski,我不知道那里有什么引号,你完全正确。至于解决方案本身:你可能是正确的为好,但我会推迟宣布这一解决,以防万一有一个更好的(我指的是更雄辩)解决方案。 – Kamarutu

+1

一种替代是使用结构(可能具有'(:类型列表)'),在这种情况下,可以使用访问器的插槽。 – jkiiski

回答

5

的是不超过lambda更好的办法:

(defvar *my-list* '((:x 1 :y something) (:x 5 :y something) (:x 19 :y something))) 
(sort *my-list* #'> :key (lambda (plist) (getf plist :x))) 
==> ((:X 19 :Y SOMETHING) (:X 5 :Y SOMETHING) (:X 1 :Y SOMETHING)) 

你可能会寻找currying,但Common Lisp的不具有开箱即用的。

Rainer的答案提供特设钻营。

+1

和[cl21](https://lispcookbook.github.io/cl-cookbook/cl21.html)的更短版本:'(sort * my-list *#'>:key ^(getf%:x)) ':) – Ehvince

8

如果使用性能的一个关键是在你的Lisp代码常见的,那么你可以定义一个函数来创建密钥的功能。请参阅使用property-key-fn

CL-USER 22 > (defparameter *my-list* (copy-list '((:x 1 :y foo) 
                (:x 5 :y bar) 
                (:x 19 :y baz)))) 
*MY-LIST* 

CL-USER 23 > (defun property-key-fn (property) 
       (lambda (plist) 
       (getf plist property))) 
PROPERTY-KEY-FN 

CL-USER 24 > (setf *my-list* (sort *my-list* #'> :key (property-key-fn :x))) 
((:X 19 :Y BAZ) (:X 5 :Y BAR) (:X 1 :Y FOO)) 

CL-USER 25 > (setf *my-list* (sort *my-list* #'string> :key (property-key-fn :y))) 
((:X 1 :Y FOO) (:X 19 :Y BAZ) (:X 5 :Y BAR)) 
+0

当我发现自己做了很多事情时,我使用了类似property-key-fn的名称,但将名称缩短为= getf。 – Xach