English 中文(简体)
用Lisp从列表中过滤掉不符合谓词条件的结果。
原标题:lisp filter out results from list not matching predicate

I am trying to learn lisp, using emacs dialect and I have a question. let us say list has some members, for which predicate evaluates to false. how do I create a new list without those members? something like { A in L: p(A) is true }. in python there is filter function, is there something equivalent in lisp? if not, how do I do it?

谢谢 (xiè xiè)

最佳回答

这些函数在CL包中,您需要(require cl)才能使用它们:

(remove-if-not # evenp  (1 2 3 4 5))

这将返回一个带有参数中所有偶数的新列表。

另见delete-if-not,该编码相同,但修改了其论点清单。

问题回答

如果您在代码中经常操作列表,请使用现代的函数式编程库dash.el,而不是编写样板代码和重新发明轮子。它拥有处理列表、树、函数应用和流程控制的所有函数,您可以想象的每一个。要保留所有满足谓词的元素并删除其他元素,您需要使用-filter

(-filter (lambda (x) (> x 2))  (1 2 3 4 5)) ; (3 4 5)

其他感兴趣的功能包括-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 的优点在于它支持指代宏。指代宏的行为类似于函数,但它们允许特殊语法使代码更加简洁。不需要提供匿名函数作为参数,只需编写S表达式并使用 it 代替局部变量,如前面的示例中的 x 。相应的指代宏以两个破折号而不是一个破折号开头:

(--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)

昨晚我正在寻找同样的东西,然后我在EmacsWiki上找到了 Elisp Cookbook列表/序列 部分包含过滤技术,显示了如何使用 mapcardelq 来完成此操作。我不得不修改代码以符合自己的目的,但这是原始代码:

;; 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.

Emacs现在附带库seq.el,请使用seq-remove

seq-remove (pred sequence) 
"Return a list of all the elements for which (PRED element) is nil in SEQUENCE."

使用 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)))

使用内置函数有很多方法可以从列表中过滤或选择项目,这比循环快得多。使用内置的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*来循环遍历列表,使用一些将特定条目转换为nil的函数,然后使用(remove-if nil ...)删除nil。 或者,您也可以使用mapcar或mapcar*將一個列表中的項目逐個循環執行一個特定的函數將其轉換為nil,然後再使用 (remove-if nil ...) 刪除nil。

很令人惊讶没有内置版本的过滤器,没有cl或(或者非常新的seq)。

在此提到的filter的实现(您可以在Elisp Cookbook和其他地方看到)是不正确的。它使用nil作为要删除的项的标记,这意味着如果您的列表中一开始就有nil,即使它们满足谓词,它们也会被删除。

为了纠正这个实现,需要用一个未使用过的符号(即gensym)替换nil标记。

(defun my-filter (pred list)
  (let ((DELMARKER (make-symbol "DEL")))
    (delq
      DELMARKER
      (mapcar (lambda (x) (if (funcall pred x) x DELMARKER))
              list))))




相关问题
Lisp code called from Java

Long story: I am doing a project for my functional programing class, and I thought of writing an AI controller in Lisp, for the Mario AI competition. I was looking over frameworks/libraries/ways of ...

Emacs, Zen-Coding mode, and Putty

I use emacs via Putty and since Putty doesn t send certain key combinations to the remote console I generally need to re-bind them to other key combinations. After installing the amazing Zen-Coding ...

In Which Cases Is Better To Use Clojure? [closed]

I develop in Lisp and in Scheme, but I was reading about Clojure and then I want to know, in which cases is better to use it than using Lisp or Scheme? Thanks

lambda-gtk negative pointer

I was trying to write my own put-pixel on (Gdk) pixbuf in Lisp. When I finally realized how I can operate on C pointers in CL, new obstacle came along - (gdk:pixbuf-get-pixels pb) returns me negative ...

Is there a common lisp package naming convention?

I have created some of my own user packages and have run into a name clash. In Java, the naming convention is to use your domain name in the package name: e.g. import com.example.somepackage;. Are ...

SOAP request from within an AutoLISP/AutoCAD macro

We have built a webservice for a client that uses AutoCAD. They have a macro that runs in AutoCAD that builds a SOAP request. But they have not figured out how to actually send() the soap request to ...

热门标签