Reputation: 77
What I'm trying to do: I want to define a function create-record
that accepts a variable number of parameters (names called keys) and generates a dynamic plist/named list.
I'm just trying to get it working with dynamic names first and assign 1 to all the names to create a list like (:x 0 :y 0 :z 0)
then I can modify it to accept both keys and values (instead of just 0 for everything key)
My code:
(defparameter *test* '('x 'y 'z))
(defun create-record (&rest keys)
(let ((count 0))
(mapcan (lambda (key) (list key count)) keys)))
Output
(create-record-variable *test*)
==> (('X 'Y 'Z) 0)
Expected Output:
(create-record-variable *test*)
==> (:x 0 :y 0 :z 0)
I'm not sure why the output is like (('X 'Y 'Z) 0)
.
Upvotes: 1
Views: 135
Reputation: 60054
The problem is not with the function, but with the invocation. What you need to do is
(create-record 'a :b '#:c)
==> (A 0 :B 0 #:C 0)
or, if the keywords are in a list,
(defparameter *test* '(:x :y :z))
(apply #'create-record *test*)
==> (:X 0 :Y 0 :Z 0)
If you want to pass the list as the argument, you can just drop &rest
.
Answering the question in the comment, here is how to create an alist (association list):
(defun make-alist (keys values)
(mapcar #'cons keys values))
(defparameter *my-alist* (make-alist '(:a :b :c) '(1 2 3)))
(assoc :a *my-alist*)
==> (:A . 1)
and a plist (property list):
(defun make-plist (keys values)
(mapcan #'list keys values))
(defparameter *my-plist* (make-plist '(:a :b :c) '(1 2 3)))
(getf *my-plist* :b)
==> 2
Upvotes: 1
Reputation: 9965
(defun make-keyword (x)
"Make out of symbol or string a keyword."
(values (intern (string x) "KEYWORD")))
;; this is equivalent to alexandria's `alexandria::make-keyword
;; (defun make-keyword (x)
;; (read-from-string (concatenate 'string ":" (string x))))
;; ;; this doesn't work with "such strings"
(defun create-record (list-of-symbols &key (count 0))
(mapcan #'(lambda (x) (list (make-keyword x) count)) list-of-symbols))
Then call it:
(defparameter *test* (list 'x 'y 'z))
(create-record *test*)
;; => (:X 0 :Y 0 :Z 0)
(create-record *test* :count 3)
;; => (:X 3 :Y 3 :Z 3)
Upvotes: 1