2017-07-24 2 views
3

Je suis en train de trier une liste qui ressemble à ceci:fonction de tri Lisp clé

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

Je suis en train de faire le tri par la valeur :x. Je pourrais faire ça comme ça

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

mais je préfère de beaucoup utiliser la fonction getf au lieu de second, mais je ne peux pas comprendre comment passer :x comme paramètre. De ce que je peux rassembler juste #'getf renvoie (getf ((:x 1 :y something) '(:x 5 :y something) (:x 19 :y something)) [external]. Comment ferais-je passer le :x comme deuxième paramètre?

La seule façon que je pourrais penser est de créer une fonction de wrapper pour getf, qui prend seulement une liste en tant que paramètre et passe en :x par défaut. Il doit y avoir une meilleure façon cependant.

+3

Vous n'avez pas besoin de citer les sous-listes dans une liste entre guillemets. En outre, vous ne devez pas utiliser des opérations destructives comme 'SORT' sur des listes (littérales) entre guillemets. Vous pouvez utiliser 'COPY-LIST' (ou' COPY-TREE') pour faire une copie de la liste avant le tri. Pour le problème lui-même, faire une fonction wrapper est la solution habituelle. C'est communément appelé currying. La bibliothèque [Alexandria] (https://common-lisp.net/project/alexandria/) a les fonctions 'CURRY' et' RCURRY' pour cela. – jkiiski

+0

@jkiiski, je ne sais pas ce qui s'est passé là-bas avec des citations, vous avez tout à fait raison. Pour ce qui est de la solution elle-même: vous avez probablement raison, mais je vais arrêter de le dire, au cas où il y aurait une meilleure solution (par laquelle je veux dire plus éloquente). – Kamarutu

+1

Une alternative serait d'utiliser des structures (éventuellement avec '(: type list)'), auquel cas vous pouvez utiliser l'accesseur pour le slot. – jkiiski

Répondre

5

Le pas de meilleure façon que 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)) 

Vous cherchez peut-être currying, mais Common Lisp n'a pas OOTB.

Rainer La réponse offre des offres spéciales.

+1

et une version plus courte avec [cl21] (https://lispcookbook.github.io/cl-cookbook/cl21.html): '(sort * ma-liste * # '>: touche^(getf%: x)) ':) – Ehvince

8

Si l'utilisation d'une propriété comme clé est courante dans votre code Lisp, vous pouvez définir une fonction pour créer la fonction de clé. Voir l'utilisation de 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

Quand je me retrouve souvent à faire cela, j'utilise quelque chose comme property-key-fn mais raccourcis le nom à = getf. – Xach