我有以下代码,它应该是一个高阶函数,它根据输入的 &key
参数过滤元素(在本例中为:year
,:month
和{{ 1}}。
:type
问题在于,除非使用所有关键字参数,否则它将始终返回 (defun filter-by (&key year month type)
"Remove members of the list not matching the given year and/or month and/or type, returns a
function that takes the list"
(lambda (lst)
(remove-if-not #'(lambda (element)
(when year
(equalp (local-time:timestamp-year (get-record-date element))
year)))
(when month
(equalp (local-time:timestamp-month (get-record-date element))
month)))
(when type
(equalp (get-type element)
type))))
lst)))
,我猜是因为nil
形式在when
内的行为1}}。
无论如何不使用多个remove-if-not
语句来完成这项工作? cond
的问题在于我必须专门写下所有可能的参数组合,这对于3个参数是可以的,但是如果将来它很难扩展我想使用其他关键字进行过滤。
答案 0 :(得分:2)
Common Lisp的关键字参数有一个特殊的语法,可以告诉你 是否提供参数。我认为你应该可以使用 这可以实现你想要的。
这是一个工作示例,尽管数据表示略有不同
因为我没有local-time
和get-record-date
的定义。您
应该能够轻松地将其适应您的代码。
(defun my-filter-by (lst &key
(year nil year-p) ;; nil is the default
(month nil month-p) ;; year-p/month-p/day-p say whether
(day nil day-p)) ;; the argument was supplied
(remove-if-not
(lambda (element)
(let* ((year-okp (or (not year-p)
(equal year (cdr (assoc :year element)))))
(month-okp (or (not month-p)
(equal month (cdr (assoc :month element)))))
(day-okp (or (not day-p)
(equal day (cdr (assoc :day element)))))
(all-okp (and year-okp month-okp day-okp)))
all-okp))
lst))
还有一些例子:
(defparameter *lst* '(((:year . 2000) (:month . :may) (:day . 17))
((:year . 2000) (:month . :may) (:day . 18))
((:year . 2001) (:month . :aug) (:day . 2))
((:year . 2002) (:month . :jan) (:day . 5))))
(my-filter-by *lst*) ;; keeps everything
(my-filter-by *lst* :year 2000) ;; everything from 2000
(my-filter-by *lst* :year 2000 :day 17) ;; only 2000 / may 17