Reputation: 274
I have a list of queue names in the following form:
'("foo" "bar")
I am trying to store queues as assoc list in the following way:
'(("foo" . nil) ("bar" . nil))
Basically it is an assoc list with queues "foo" and "bar" which are currently empty. When Bob and Alice will be in the "foo" queue it should look like the following.
'(("foo" . ("alice" "bob")) ("bar" . nil))
How can I create this structure? I tried to achieve that by writing:
(mapcar #'(lambda (x) (cons x ''nil)) '("foo" "bar"))
which returned
'(("foo" QUOTE NIL) ("bar" QUOTE NIL))
this is probably not what I wanted because when I tried to push Bob to the "foo" queue it doesn't work as I wanted.
* (setf *tmp* '(("foo" . 'nil) ("bar" . 'nil)))
(("foo" QUOTE NIL) ("bar" QUOTE NIL))
* (push "bob" (caddr (assoc "foo" *tmp* :test #'string=)))
* *tmp*
(("foo" QUOTE ("bob")) ("bar" QUOTE NIL))
How can I create dotted pair with empty list after the dot?
EDIT: Actually when I store such assoc list as the class slot it looks fine.
* (describe myClassInstance)
;; ...
QUEUES = (("foo" . 'NIL) ("bar" . 'NIL))
;; ...
However after writing adding Bob to the "foo" queue all queues are being changed.
* (push "bob" (caddr (assoc "foo" (slot-value myClassInstance 'testClass::queues) :test #'string=))))
* (describe myClassInstance)
;; ...
QUEUES = (("foo" . '("bob") ("bar" . '("bob"))
;; ...
What just happened here? It looks like the cdr
part of all the queues was a single symbol and when I changed it's value in one place ("foo" queue) then it was changed in all the places (all the queues). Does it make any sense?
Upvotes: 0
Views: 485
Reputation: 139261
Compare with dots
CL-USER 48 > (sdraw '(("foo" . ("alice" "bob")) ("bar" . nil)))
[*|*]---------------------------->[*|*]--->NIL
| |
v v
[*|*]--->[*|*]---->[*|*]--->NIL [*|*]--->NIL
| | | |
v v v v
"foo" "alice" "bob" "bar"
and without dots
CL-USER 49 > (sdraw '(("foo" "alice" "bob") ("bar")))
[*|*]---------------------------->[*|*]--->NIL
| |
v v
[*|*]--->[*|*]---->[*|*]--->NIL [*|*]--->NIL
| | | |
v v v v
"foo" "alice" "bob" "bar"
So, both notations are describing the same cons structure.
Upvotes: 2
Reputation: 51501
A cons where the cdr is nil is exactly the same as a one-element list. This is how lists are defined.
In other words, (cons x nil)
is the same as (list x)
. You can imagine the result like this:
+-------+
| x |nil|
+-------+
A dotted pair where the cdr is a list is thus also just a list.
In other words, '(("foo" . nil) ("bar" . nil))
is exactly the same as '(("foo") ("bar"))
, even if the former notation perhaps better conveys your intent of treating it as an alist.
In the same way, '(("foo" . ("alice" "bob")) ("bar" . nil))
is exactly the same as '(("foo" "alice" "bob") ("bar"))
.
This means that you can create your data structure exactly as you want, but you can use e. g. list
instead of (lambda (x) (cons x nil))
(which is the same for a single argument).
(defun make-queues (&rest names)
(mapcar #'list names))
You can also just push to the element found by assoc
under a name:
(defun add-to-queue (queues queue-name item)
(push item (cdr (assoc queue-name queues :test #'equal))))
(defun get-queue (queues queue-name)
(cdr (assoc queue-name queues :test #'equal)))
The problem that you had last was that you put a literal into a list and tried to modify it: you put the same literal list containing only nil
into each element of your alist.
Upvotes: 4
Reputation: 1934
I think you are probably confusing the structure with its printed representation. (cons x nil)
is the same as '(x . nil)
and the same as '(x)
. They will all print as (x)
.
If you want to print as '(x . nil)
you can write a print function for it, but the representations is perfectly fine.
Upvotes: 5