Azeirah
Azeirah

Reputation: 6338

Modifying a property list

I have a property list:

(setf *star* '(:points 5))

I'd like to modify this plist. Sometimes the better choice is to do mutation, and sometimes the better choice is to use an immutable update.

How to modify the plist using mutation?

(mutate *star* :points 6)
*star* ; '(:points 6)

And how to modify the plist using an immutable update?

(update *star* :points 6) ; '(:points 6)
*star*                    ; '(:points 5)

Upvotes: 3

Views: 1234

Answers (2)

Throw Away Account
Throw Away Account

Reputation: 2671

To mutate a plist, just use setf:

(setf (getf *star* :points) 59)

To do a non-mutative update, where the original value is left undisturbed, you might do something like this:

(defun update-plist (plist indicator new-value)
    (let ((other-properties nil))
      (loop while plist
            for property = (pop plist)
            for value = (pop plist)
            when (eq property indicator)
            do (return-from update-plist (list* property new-value
                                                (append other-properties plist)))
            else do (push value other-properties)
                    (push property other-properties))
      (list* indicator new-value other-properties)))

It differs from your example:

*star* ;; (:points 6 :color :green)
(update-plist *star* :points 5) ;; (:points 5 :color :green)
*star* ;; (:points 6 :color :green) -- Doesn't change.

Upvotes: 2

sds
sds

Reputation: 60014

What you are looking for are getf and maybe get-properties. To modify the plist non-destructively, use list*:

(setq *star* (list* :points 6 *star*))

If your plist is associated with a symbol, you should use get and remprop.

NB: it is a much better idea to use association lists (see assoc and acons) because they are more flexible (e.g., it is easier to switch from associating multiple objects with a key using alists).

Upvotes: 4

Related Questions