我想做
(filter-list-into-two-parts #'evenp '(1 2 3 4 5))
; => ((2 4) (1 3 5))根据谓词的计算结果是否为true,将列表拆分为两个子列表。很容易定义这样一个函数:
(defun filter-list-into-two-parts (predicate list)
(list (remove-if-not predicate list) (remove-if predicate list)))但是我想知道在Lisp中是否有一个内置函数可以做到这一点,或者是否有一种更好的方法来编写这个函数?
发布于 2013-08-08 02:34:37
我不认为有内置的,而且您的版本是次优的,因为它遍历列表两次,并在每个list元素上调用两次谓词。
(defun filter-list-into-two-parts (predicate list)
(loop for x in list
if (funcall predicate x) collect x into yes
else collect x into no
finally (return (values yes no))))我返回两个值,而不是其中的列表;这更符合惯例(您将使用multiple-value-bind从返回的多个值中提取yes和no,而不是使用destructuring-bind来解析列表,而是更少、更快,参见通用Lisp中的值函数)。
更一般的版本是
(defun split-list (key list &key (test 'eql))
(let ((ht (make-hash-table :test test)))
(dolist (x list ht)
(push x (gethash (funcall key x) ht '())))))
(split-list (lambda (x) (mod x 3)) (loop for i from 0 to 9 collect i))
==> #S(HASH-TABLE :TEST FASTHASH-EQL (2 . (8 5 2)) (1 . (7 4 1)) (0 . (9 6 3 0)))发布于 2013-08-08 07:34:38
使用REDUCE
(reduce (lambda (a b)
(if (evenp a)
(push a (first b))
(push a (second b)))
b)
'(1 2 3 4 5)
:initial-value (list nil nil)
:from-end t)发布于 2013-08-10 16:14:19
我认为在普通的lisp标准中没有分区函数,但是有库提供了这样一个实用程序(包括文档和来源)。
CL-USER> (ql:quickload :arnesi)
CL-USER> (arnesi:partition '(1 2 3 4 5) 'evenp 'oddp)
((2 4) (1 3 5))
CL-USER> (arnesi:partition '(1 2 b "c") 'numberp 'symbolp 'stringp)
((1 2) (B) ("c"))https://stackoverflow.com/questions/18116949
复制相似问题