通过谓词将列表过滤成两部分

标签 filter lisp common-lisp

我想做

(filter-list-into-two-parts #'evenp '(1 2 3 4 5))
; => ((2 4) (1 3 5))

根据谓词的计算结果是否为真,列表被分成两个子列表。定义这样一个函数很容易:

(defun filter-list-into-two-parts (predicate list)
  (list (remove-if-not predicate list) (remove-if predicate list)))

但我想知道 Lisp 中是否有内置函数可以执行此操作,或者是否有更好的编写此函数的方法?

最佳答案

我不认为有内置的,你的版本不是最优的,因为它遍历列表两次并对每个列表元素调用谓词两次。

(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 从返回的多个值中提取 yesno,而不是使用 destructuring-bind 来解析列表,它包含更少,更快,另见 values function in Common 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)))

关于通过谓词将列表过滤成两部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18116949/

相关文章:

CSS Filter 被后台停止

lisp - Dribble 正在生成空的输出文件

lisp - 使用带有一个或多个符号的 case

java - 如何使用java实现低通滤波器

php - 如何在 Yii 中添加搜索和过滤条件

lambda - (self self) 在 let 语句中调用,用严格的语言

concurrency - 想要一个简单的程序来说明使用线程并发 lisp 的使用

common-lisp - 如何创建由 `make-symbol` 创建的符号

json - JQ 选择存在内键的对象

recursion - Lisp 中的递归加法