lisp filtrer les résultats de la liste ne correspond pas prédicat

j'essaie d'apprendre le lisp, en utilisant le dialecte emacs et j'ai une question. disons que list a quelques membres, pour lesquels predicate évalue à faux. comment créer une nouvelle liste sans ces membres? quelque chose comme { A in L: p(A) is true }. en python il y a une fonction de filtre, y a-t-il quelque chose d'équivalent dans lisp? si non, comment dois-je faire?

Merci

34
demandé sur Teddy 2010-02-10 09:25:42

7 réponses

ces fonctions sont dans le paquet CL, vous aurez besoin de (require 'cl) utiliser:

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

retourne une nouvelle liste avec tous les nombres pairs de l'argument.

rechercher delete-if-not, qui fait de même, mais modifie sa liste d'arguments.

42
répondu rootzlevel 2014-09-13 22:42:32

si vous manipulez des listes lourdement dans votre code, s'il vous plaît utilisez dash.el moderne fonctionnelle de la programmation de la bibliothèque, au lieu d'écrire du code réutilisable et à réinventer la roue. Il a toutes les fonctions pour travailler avec des listes, des arbres, l'application de fonction et le contrôle de flux que vous pouvez jamais imaginer. Pour garder tous les éléments qui correspondent à un prédicat et supprimer les autres, vous avez besoin -filter:

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

les autres fonctions d'intérêt comprennent -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)

Ce qui est formidable à propos de dash.el c'est qu'il prend en charge macros anaphoriques. Les macros anaphoriques se comportent comme des fonctions, mais elles permettent une syntaxe spéciale pour rendre le code plus concis. Au lieu de fournir un fonction anonyme comme argument, il suffit d'écrire un s-expression et utiliser it au lieu d'une variable locale, comme x dans les exemples précédents. Correspondant les macros anaphoriques commencent avec 2 tirets au lieu d'un:

(--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)
21
répondu Mirzhan Irkegulov 2014-08-03 16:32:31

je cherchais la même chose la nuit dernière et je suis tombé sur le Elisp Livre De CuisineEmacsWiki. la section sur les listes / séquences contient des teqniques de filtrage et montre comment faire avec mapcar et delq. J'ai du mod le code pour l'utiliser pour mes propres fins, mais voici l'original:

;; 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.
19
répondu kjfletch 2017-06-03 18:12:34

Emacs est maintenant livré avec la bibliothèque seq.el, utilisez seq-remove.

seq-remove (pred sequence) 
"Return a list of all the elements for which (PRED element) is nil in SEQUENCE."
4
répondu Joelmob 2017-02-03 15:31:49

Avec common lisp, vous pouvez implémenter la fonction comme suit:

(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)))
0
répondu prosseek 2015-08-28 23:55:48

c'est surprenant il n'y a pas de version intégrée de filter sans cl ou (ou seq ce qui est très nouveau).

la mise en oeuvre de filter mentionné ici (ce que vous voyez dans le Livre de recettes D'Elisp et ailleurs) est incorrect. Il utilise nil comme marqueur pour les éléments à supprimer, ce qui signifie Si vous avez nils dans votre liste pour commencer, ils vont être supprimée, même si elles satisfont le prédicat.

pour corriger cette implémentation, le nil besoin de marqueurs à remplacer par un symbole sans coupure (c.-à-d. gensym).

(defun my-filter (pred list)
  (let ((DELMARKER (make-symbol "DEL")))
    (delq
      DELMARKER
      (mapcar (lambda (x) (if (funcall pred x) x DELMARKER))
              list))))
0
répondu pyrocrasty 2017-04-24 15:30:14

il y a une tonne de façons de filtrer ou de sélectionner des trucs d'une liste en utilisant des built-ins qui sont beaucoup plus rapides que des boucles. Le haut-supprimer-si peut être utilisé de cette façon. Par exemple, supposons que je veuille laisser tomber les éléments 3 à 10 dans la liste MyList. Exécutez le code suivant comme exemple:

(let ((MyList (number-sequence 0 9))
      (Index -1)
      )
  (remove-if #'(lambda (Elt)
                  (setq Index (1+ Index))
                  (and (>= Index 3) (<= Index 5))
                  )
              MyList
           )
 )

vous obtiendrez '(0 1 2 6 7 8 9).

supposons que vous voulez garder seulement des éléments entre 3 et 5. Tu retournes la condition que j'ai écrite ci-dessus dans le prédicat.

(let ((MyList (number-sequence 0 9))
      (Index -1)
      )
  (remove-if #'(lambda (Elt)
                   (setq Index (1+ Index))
                   (or (< Index 3) (> Index 5))
                  )
              MyList
           )
 )

Vous obtiendrez '(3 4 5)

Vous pouvez utiliser ce que vous avez besoin pour le prédicat que vous devez fournir à supprimer-si. La seule limite est votre imagination sur ce qu'il faut utiliser. Vous pouvez utiliser les fonctions de filtrage de séquence, mais vous n'en avez pas besoin.

vous pouvez aussi utiliser mapcar ou mapcar* pour boucler une liste en utilisant une fonction qui fait tourner des entrées spécifiques à zéro et l'utilisation (Supprimer-si nul ...) à la chute de nils.

0
répondu Pablo A Perez-Fernandez 2017-06-22 22:54:58