testgauss321
testgauss321

Reputation: 77

how can I modify this function to create a dynamic plist

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

Answers (2)

sds
sds

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

Gwang-Jin Kim
Gwang-Jin Kim

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

Related Questions