2011-01-29 5 views
5

me gustaría hacer:mapcar y asoc

(mapcar #'assoc '(a s) '((a . b) (c . d) (s . f))) 

y tienen que volver

((A . B) (S . F)) 

que parece bastante razonable, teniendo en cuenta los rendimientos (assoc 'a '((a . b) (c . d) (s . f)))(A . B) y (assoc 's '((a . b) (c . d) (s . f))) vuelve (S . F). Pero, por desgracia, no funciona:

*** - ASSOC: A is not a list 
The following restarts are available: 
ABORT   :R1  Abort main loop 

¿Alguna idea?

Respuesta

7

Cuando se usa con dos listas, mapcar aplica la función por pares a las listas (y con tres listas las aplica con triple sentido, etc.). Así

(mapcar #'assoc '(a s) '((a . b) (c . d) (s . f))) 

es la misma que

((assoc 'a (a . b)) (assoc 's (c . d))) 

(cuando se utiliza con listas de diferente longitud, mapcar utiliza el tamaño de la lista más pequeño). Para obtener lo que desea, debe hacer:

(mapcar (lambda (x) (assoc x '((a . b) (c . d) (s . f)))) '(a s)) 
5

Necesitamos otro nivel de lista. El segundo argumento debería ser una lista de listas de asociaciones.

CL-USER > (mapcar #'assoc '(a s) '(((a . b) (c . d) (s . f)))) 

((A . B)) 

Pero el segundo argumento tiene solo un elemento de longitud. Ahora podemos usar un truco y que sea una lista circular:

CL-USER > (mapcar #'assoc '(a s) '#1=(((A . B) (C . D) (S . F)) . #1#)) 

((A . B) (S . F)) 

Si construimos una lista circular para el segundo argumento, entonces funciona.

En función:

(defun circular (list) 
    (if (null list) 
     list 
    (setf (cdr (last list)) list))) 

CL-USER > (mapcar #'assoc '(a s) (circular '(((a . b) (c . d) (s . f))))) 

((A . B) (S . F)) 
+0

Niza. Realmente me gusta eso. – rhombidodecahedron

Cuestiones relacionadas