Common Lisp - 是否有内置函数来按键过滤plist?

boe*_*107 1 common-lisp plist

我正在寻找如下的内置函数pfilter-by-keys:

(pfilter-by-keys '(:a :b) '(:c 10 :b 20 :a 4))
;; => (:B 20 :A 4)
Run Code Online (Sandbox Code Playgroud)

它的代码非常简单:

(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)))
Run Code Online (Sandbox Code Playgroud)

CL有一些像上面那样的内置函数吗?

PS.:亚历山大有一个非常接近的功能:remove-from-plist.

Rai*_*wig 5

CL:GET-PROPERTIES 是一个积木:

(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)))
Run Code Online (Sandbox Code Playgroud)

请注意,最好是两次收集,而不是在a中追加/列表LOOP.


Dan*_*son 5

没有执行此操作的功能(这不是人们通常想做的事情)

有一个宏remf可以从某个地方的 plist 中删除一个键。

实现这一目标的另一种方法是:

(destructuring-bind (&key (a nil ap) (b nil bp) &allow-other-keys) plist
  (append (if ap (list :a a)) (if bp (list :b b))))
Run Code Online (Sandbox Code Playgroud)

但请注意,这只适用于您已经知道要保留哪些键的情况,并且这不会保留 plist 中的顺序,也不会保留重复的键(即,如果您的 plist:a多次包含该键,则结果将只包含一次)。

您可以使用通用(符号)键的普通 lambda 列表语法为非关键字键修改此设置。