Reputation: 1724
I'm looking for a built-in function like the pfilter-by-keys
below:
(pfilter-by-keys '(:a :b) '(:c 10 :b 20 :a 4))
;; => (:B 20 :A 4)
Its code is pretty simple:
(defun pfilter-by-keys (keys plist)
"List -> PList -> PList
Returns a new plist with only the keys/values correspondent to the given
keys."
(loop for (k v) on plist by #'cddr
when (member k keys :test #'equal)
append (list k v)))
Does CL has some built-in function like the one above?
PS.: Alexandria has a very close function: remove-from-plist
.
Upvotes: 1
Views: 1546
Reputation: 4360
There is no function to do this (and this isn’t the sort of thing one usually wants to do)
There is a macro remf
which removes a key from a plist in some place.
Another way you might achieve this is by:
(destructuring-bind (&key (a nil ap) (b nil bp) &allow-other-keys) plist
(append (if ap (list :a a)) (if bp (list :b b))))
But note that this only works if you already know what keys you want to keep and this does not preserve the order in the plist and it does not preserve repeated keys (i.e. if your plist contains the key :a
multiple times the result will contain it only once).
You can modify this for non keyword keys using the normal lambda list syntax for general (symbol) keys.
Upvotes: 5
Reputation: 139381
CL:GET-PROPERTIES
is a building block:
(defun keep-properties (plist indicator-list &aux k v)
"Keeps all property list entries for a given indicator-list."
(loop do (setf (values k v plist)
(get-properties plist indicator-list))
while plist
collect k collect v
do (pop plist) (pop plist)))
Note, that it is better to collect twice, than to append/list in a LOOP
.
Upvotes: 5