Mapcar и ст.н.с

Бих искал да направя:

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

и го върнете

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

Което изглежда доста разумно, като се има предвид, че (assoc 'a '((a . b) (c . d) (s . f))) връща (A . B) и (assoc 's '((a . b) (c . d) (s . f))) връща (S . F). Но уви не работи:

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

някакви мисли?


person rhombidodecahedron    schedule 29.01.2011    source източник


Отговори (2)


Когато се използва с два списъка, mapcar прилага функцията по двойки към списъците (а с три списъка ги прилага тройно и т.н.). Така

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

е същото като

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

(когато се използва със списъци с различна дължина, mapcar използва размера на най-малкия списък). За да получите това, което искате, трябва да направите:

(mapcar (lambda (x) (assoc x '((a . b) (c . d) (s . f)))) '(a s))
person sepp2k    schedule 29.01.2011

Имаме нужда от друго ниво на списък. Вторият аргумент трябва да бъде списък с асоциирани списъци.

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

((A . B))

Но вторият аргумент е дълъг само един елемент. Сега можем да използваме трик и да го направим кръгъл списък:

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

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

Ако изградим кръгъл списък за втория аргумент, тогава той работи.

Като функция:

(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))
person Rainer Joswig    schedule 30.01.2011