[alexandria-devel] Implementation of DELETE-FROM-PLIST

Robert Smith quad at symbo1ics.com
Sat Feb 23 09:15:18 UTC 2013


Attached is a proper patch.

-Robert

On Sat, Feb 23, 2013 at 1:09 AM, Robert Smith <quad at symbo1ics.com> wrote:
> Hey:
>
> Here's a destructive/non-consing version of DELETE-FROM-PLIST. I've
> tested with (I think) all corner cases from the REPL, but I ought to
> write tests proper.
>
> The function is here http://tinyurl.com/adqkssu ;or the following huge
> link, in case the last one is invalidated
> https://bitbucket.org/tarballs_are_good/lisp-random/src/3db634111d35e788c6ea2f4a1b3ab38334e24cde/miscellaneous_exercises/delete-from-plist.lisp?at=default#cl-30
> .
>
> For simplicity or ease of review from an email client, I've pasted the
> function at the end of this email.
>
> Additionally, this function would make it pretty easy to write
> DELETE-FROM-PLIST-IF{-NOT}, since the function to determine if a key
> is bad is factored out. If one did write this function, then it would
> be easy to define DELETE-FROM-PLIST in terms of it.
>
> Let me know if there are any changes that should be made.
>
> Cheers,
>
> Robert Smith
>
>
> ;;;; from delete-from-plist.lisp
>
> (defun delete-from-plist (plist &rest keys)
>   "Delete all keys and pairs indicated by KEYS from the plist PLIST."
>   (labels ((assert-proper-plist (x)
>              (assert x () "Expected a proper plist, got ~S" plist))
>            (bad-key-p (key)
>              (member key keys :test #'eq))
>            (find-first ()
>              "Find the first cons in PLIST to keep."
>              (loop :for the-cons :on plist :by #'cddr
>                    :unless (prog1 (bad-key-p (car the-cons))
>                              (assert-proper-plist (cdr the-cons)))
>                      :do (return the-cons)
>                    :finally (return nil))))
>     (declare (inline assert-proper-plist
>                      bad-key-p
>                      find-first))
>     ;; Find the first good key and delete any bad key-value pairs
>     ;; between it and the start.
>     (let ((first (find-first)))
>       (unless (eq first plist)
>         (setf (cddr plist)
>               first))
>
>       ;; At this point, we know FIRST points to the first key
>       ;; which exists, or NIL.
>       (loop :with last-good := first    ; Keep the last good key
>             :for the-cons :on (cddr first) :by #'cddr
>             :do (progn
>                   (assert-proper-plist (cdr the-cons))
>                   (if (bad-key-p (car the-cons))
>                       (setf (cddr last-good)
>                             (cddr the-cons))
>                       (setf last-good the-cons)))
>             :finally (return first)))))
-------------- next part --------------
A non-text attachment was scrubbed...
Name: delete-from-plist.diff
Type: application/octet-stream
Size: 1925 bytes
Desc: not available
URL: <https://mailman.common-lisp.net/pipermail/alexandria-devel/attachments/20130223/3d7ee3ba/attachment.obj>


More information about the alexandria-devel mailing list