使用带有 &key 参数的 remove-if-not
Using remove-if-not with &key parameters
我有以下代码,它应该是一个高阶函数,它根据输入的 &key
参数过滤元素(在本例中为 :year
、:month
和: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)))
问题是,除非使用 all 关键字参数,否则它将始终 return nil
,我猜是因为 when
表单在 remove-if-not
.
内运行
有没有办法在不求助于多个 cond
语句的情况下完成这项工作? cond
的问题是我必须 特别地 写下所有可能使用的参数组合,这对于 3 个参数是可以的,但是如果将来我想使用其他关键字进行过滤。
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
我有以下代码,它应该是一个高阶函数,它根据输入的 &key
参数过滤元素(在本例中为 :year
、:month
和: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)))
问题是,除非使用 all 关键字参数,否则它将始终 return nil
,我猜是因为 when
表单在 remove-if-not
.
有没有办法在不求助于多个 cond
语句的情况下完成这项工作? cond
的问题是我必须 特别地 写下所有可能使用的参数组合,这对于 3 个参数是可以的,但是如果将来我想使用其他关键字进行过滤。
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