2010-02-10 3 views
31

나는 이맥스 방언을 사용하여 혀짤배기를 배우려고 노력 중이며 질문이 있습니다. list에 predicates가 false로 평가되는 일부 구성원이 있다고합시다. 그 회원이없는 새리스트를 어떻게 만듭니 까? { A in L: p(A) is true }과 같은 것입니다. 파이썬에는 필터 함수가 있습니다. 리스프에 상응하는 것이 있습니까? 그렇지 않다면 어떻게해야합니까?lisp는 술어와 일치하지 않는 목록의 결과를 필터링합니다.

답변

38

이 기능은 CL의 패키지에

덕분에, 당신이 그들을 사용하는 (require 'cl)해야합니다

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

이는 인수의 모든 짝수로 새 목록을 반환합니다.

동일한 작업을 수행하지만 인수 목록을 수정하는 delete-if-not도 조회합니다.

+6

Common Lisp [¹] (http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/)에서'# 'remove-if-not' 함수가 사용되지 않을 것이라는 점을 지적하고자합니다. if (remove-if ('evenp)'(1 2 3 4 5))'또는 단순히'(remove-if # 'oddp') 필터가 쓰여지는 곳의 하이퍼 스펙/바디/fun_removecm__elete- (1 2 3 4 5))'- 필자의 지식으로는 Emacs Lisp에는'complement '함수가 존재하지 않습니다. –

+1

Pls는 * cl-lib * 패키지를 사용하고 ** cl-remove-if-not ** ** 기능을 대신 사용합니다. –

19

어젯밤에 매우 똑같은 것을 찾고 있었는데 Elisp CookbookEmacsWiki에 발견했습니다. The section on Lists/Sequences에는 필터링 기법이 포함되어 있으며 mapcardelq을 사용하여 필터링 방법을 보여줍니다. 나는 내 자신의 목적을 위해 사용하는 코드를 MOD했다하지만 여기에 원래이다 :

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

링크가 끊어졌습니다. 새 위치는 http://www.emacswiki.org/emacs/ElispCookbook#toc37입니다 (하지만 stackoverflow는 6 자 미만의 문자를 수정하지 않습니다 ...) – robru

+0

새 링크 : https://www.emacswiki.org/ emacs/ElispCookbook # toc39 – Cheeso

18

대신 상용구 코드를 작성하고 개혁의, dash.el 현대 함수형 프로그래밍 라이브러리를 사용하시기 바랍니다 코드에 많은 목록을 조작하는 경우 바퀴. 그것은 당신이 상상할 수있는 목록, 나무, 기능 응용 프로그램 및 흐름 제어와 함께 작동하는 모든 기능을 가지고 있습니다. 술어와 일치하는 모든 요소를 ​​유지하고 당신이 -filter 필요한 다른 사람을 제거하려면 다음과 관심의

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

다른 기능을 포함 -remove, -take-while, -drop-while : 그것은 anaphoric macros을 지원

큰 무엇
(-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된다 . 애너픽 매크로는 함수처럼 동작하지만 특수 구문을 사용하여 코드를보다 간결하게 만들 수 있습니다. 인수로 anonymous function을 제공하는 대신 s-expression을 작성하고 이전 예제의 x과 같은 로컬 변수 대신 it을 사용하면됩니다. 해당 anaphoric 매크로는 하나가 아닌 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) 
+0

멋진 라이브러리, 나를 가리켜 주셔서 감사합니다! – JustGage

0

, 당신은 기능을 구현할 수 있습니다

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

이맥스 지금 도서관 seq.el 함께 제공 seq-remove를 사용합니다.

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

그것은 (아주 새로운 또는 seq) cl 유무에 관계없이 필터에는 내장 버전이 없습니다 놀라운.

여기에 언급 된 filter (Elisp 요리 책 및 다른 곳에서 볼 수 있음)의 구현이 잘못되었습니다. 제거 할 항목의 마커로 nil을 사용합니다. 즉, 목록에 nil이 시작되면 술어를 만족하더라도 제거 될 것입니다.

이 구현 방법을 수정하려면 nil 마커를 중간 기호가 아닌 기호 (예 : gensym)로 바꿔야합니다.

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

루프보다 훨씬 빠른 내장 기능을 사용하여 목록에서 항목을 필터링하거나 선택할 수있는 방법은 많습니다. 내장 된 remove-if는이 방법으로 사용할 수 있습니다. 예를 들어, List MyList에 3에서 10까지 요소를 h 제하려고한다고 가정하십시오. 다음 코드를 예제로 실행하십시오.

(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로 설정하고 nil을 삭제할 때 (remove-if nil ...) 일부 기능을 사용하여 목록을 반복 할 수도 있습니다.

관련 문제