2017-07-24 110 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