我正在尝试使用emacs方言学习lisp,并且我有一个问题。让我们说列表有一些成员,对于这些成员,谓词评估为false。如何在没有这些成员的情况下创建新列表?像{ A in L: p(A) is true }
。在python中有过滤功能,在lisp中是否有相当的功能?如果不是,我该怎么做?lisp从列表中不匹配谓词过滤出结果
感谢
我正在尝试使用emacs方言学习lisp,并且我有一个问题。让我们说列表有一些成员,对于这些成员,谓词评估为false。如何在没有这些成员的情况下创建新列表?像{ A in L: p(A) is true }
。在python中有过滤功能,在lisp中是否有相当的功能?如果不是,我该怎么做?lisp从列表中不匹配谓词过滤出结果
感谢
这些功能在CL包,您将需要(require 'cl)
使用它们:
(remove-if-not #'evenp '(1 2 3 4 5))
这将返回一个新的列表与所有甚至从参数号。
也查找delete-if-not
,它做同样的事情,但修改它的参数列表。
昨晚我在找同样的东西,在EmacsWiki上遇到了Elisp Cookbook。 The section on Lists/Sequences包含过滤技术并显示如何使用mapcar
和delq
完成此操作。我不得不国防部使用它为我自己的目的的代码,但原来这里是:
;; Emacs Lisp doesn’t come with a ‘filter’ function to keep elements that satisfy
;; a conditional and excise the elements that do not satisfy it. One can use ‘mapcar’
;; to iterate over a list with a conditional, and then use ‘delq’ to remove the ‘nil’
;; values.
(defun my-filter (condp lst)
(delq nil
(mapcar (lambda (x) (and (funcall condp x) x)) lst)))
;; Therefore
(my-filter 'identity my-list)
;; is equivalent to
(delq nil my-list)
;; For example:
(let ((num-list '(1 'a 2 "nil" 3 nil 4)))
(my-filter 'numberp num-list)) ==> (1 2 3 4)
;; Actually the package cl-seq contains the functions remove-if and remove-if-not.
;; The latter can be used instead of my-filter.
如果你在你的code操作列表,请使用dash.el
现代函数式编程库,而不是写样板代码和重塑车轮。它具有与您所能想象的列表,树木,功能应用和流量控制一起工作的各种功能。为了保持匹配谓词的所有元素,并删除其他内容则需要-filter
:
感兴趣的其他功能包括-remove
,-take-while
,-drop-while
:
(-remove (lambda (x) (> x 2)) '(1 2 3 4 5)) ; (1 2)
(-take-while (lambda (x) (< x 3)) '(1 2 3 2 1)) ; (1 2)
(-drop-while (lambda (x) (< x 3)) '(1 2 3 2 1)) ; (3 2 1)
有什么了不起dash.el
是它支持anaphoric macros 。指代宏的行为与函数类似,但它们允许特殊的语法使代码更加简洁。不要提供anonymous function作为参数,只需编写s-expression并使用it
而不是本地变量,如前面示例中的x
。相应照应宏开始2个破折号,而不是一个:
(--filter (> it 2) '(1 2 3 4 5)) ; (3 4 5)
(--remove (> it 2) '(1 2 3 4 5)) ; (1 2)
(--take-while (< it 3) '(1 2 3 2 1)) ; (1 2)
(--drop-while (< it 3) '(1 2 3 2 1)) ; (3 2 1)
真棒图书馆,感谢您的指点! – JustGage 2015-02-27 08:44:10
有了Common Lisp的,可以实现的功能如下:
(defun my-filter (f args)
(cond ((null args) nil)
((if (funcall f (car args))
(cons (car args) (my-filter f (cdr args)))
(my-filter f (cdr args))))))
(print
(my-filter #'evenp '(1 2 3 4 5)))
现在的Emacs自带的库seq.el
,使用seq-remove
。
seq-remove (pred sequence)
"Return a list of all the elements for which (PRED element) is nil in SEQUENCE."
这是令人惊讶有过滤器的内置无版无cl
或(或seq
这是非常新的)。
这里提到的filter
的实现(你在Elisp Cookbook和别处看到的)是不正确的。它使用nil
作为要删除项目的标记,这意味着如果您的列表中有nil
s,那么即使它们满足谓词,它们也将被删除。
要纠正这个实现,nil
标记需要用一个未中断的符号(即。gensym)替换。
(defun my-filter (pred list)
(let ((DELMARKER (make-symbol "DEL")))
(delq
DELMARKER
(mapcar (lambda (x) (if (funcall pred x) x DELMARKER))
list))))
有一吨的过滤方法或者使用内置插件这比循环更快列表选择的东西。内置的remove-if可以这样使用。例如,假设我想在列表MyList中删除元素3到10。作为示例执行以下代码:
(let ((MyList (number-sequence 0 9))
(Index -1)
)
(remove-if #'(lambda (Elt)
(setq Index (1+ Index))
(and (>= Index 3) (<= Index 5))
)
MyList
)
)
您将得到'(0 1 2 6 7 8 9)。
假设你只想保留3到5之间的元素。你基本上翻转了我在谓词中写的上面的条件。
(let ((MyList (number-sequence 0 9))
(Index -1)
)
(remove-if #'(lambda (Elt)
(setq Index (1+ Index))
(or (< Index 3) (> Index 5))
)
MyList
)
)
你会得到“(3 4 5)
你可以使用任何你需要的,你必须提供删除,如果断言。唯一的限制是你对使用什么的想象。您可以使用序列过滤功能,但不需要它们。
或者,您也可以使用mapcar或mapcar *使用某些函数将列表中的特定条目变为零并使用(remove-if nil ...)来删除nils。
我想指出'#'remove-if-not'在Common Lisp [1]中已弃用(http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/ (remove-if(complement#'evenp)'(1 2 3 4 5))''或简单地''(remove-if#'oddp' (1 2 3 4 5))' - Emacs Lisp中并不存在函数'complement',但据我所知。 – 2011-09-25 07:19:06
请使用* cl-lib *包,并使用** cl-remove-if-not **函数作为替换。 – 2016-08-21 13:54:12