2011-01-29 5 views
5

chciałbym zrobić:Mapcar i assoc

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

i to powrócić

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

co wydaje się całkiem rozsądne, biorąc pod uwagę (assoc 'a '((a . b) (c . d) (s . f))) powraca (A . B) i (assoc 's '((a . b) (c . d) (s . f))) powraca (S . F). Ale niestety to nie działa:

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

Jakieś myśli?

Odpowiedz

7

W przypadku użycia z dwiema listami, mapcar stosuje funkcję parami do list (a przy trzech listach stosuje je trzykrotnie itd.). Więc

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

jest taka sama jak

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

(Przy użyciu list o różnej długości, mapcar wykorzystuje wielkość najmniejszego listy). Aby uzyskać to, czego chcesz, powinieneś:

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

Potrzebujemy kolejnego poziomu listy. Drugim argumentem powinna być lista list assoc.

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

((A . B)) 

Ale drugi argument ma tylko jeden element. Teraz możemy użyć podstępu i zrobić z niego okrągłą listę:

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

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

Jeśli skonstruujemy okrągłą listę dla drugiego argumentu, to działa.

Jako funkcja:

(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

Nicea. Naprawdę to lubię. – rhombidodecahedron

Powiązane problemy