tag grupo combo list lisp filter elisp predicate

list - grupo - option tags



Lisp filtra los resultados de la lista que no coincide con el predicado (7)

Con el lisp común, puede implementar la función de la siguiente manera:

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

Estoy tratando de aprender lisp, usando el dialecto de emacs y tengo una pregunta. digamos que la lista tiene algunos miembros, para los cuales el predicado se evalúa como falso. ¿Cómo creo una nueva lista sin esos miembros? algo como { A in L: p(A) is true } . en python hay función de filtro, ¿hay algo equivalente en lisp? si no, ¿cómo lo hago?

Gracias


Emacs ahora viene con la biblioteca seq.el , use seq-remove .

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


Es sorprendente que no haya una versión integrada de filtro sin cl o (o seq que es muy nuevo).

La implementación del filter mencionado aquí (que ve en el Recetario Elisp y en otros lugares) es incorrecta. Utiliza nil como un marcador para los elementos que se eliminarán, lo que significa que si tienes nil en la lista para empezar, se eliminarán incluso si satisfacen el predicado.

Para corregir esta implementación, los marcadores nil deben reemplazarse con un símbolo no interconectado (es decir, gensym).

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


Estaba buscando la misma noche y encontré el libro de cocina EmacsWiki en EmacsWiki . La sección de Listas / Secuencias contiene teqniques de filtrado y muestra cómo se puede hacer esto con mapcar y delq . Tuve que modificar el código para usarlo para mis propios fines, pero aquí está el 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.


Estas funciones están en el paquete CL, necesitarás (require ''cl) usarlas:

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

Esto devolverá una nueva lista con todos los números pares del argumento.

También busque delete-if-not , que hace lo mismo, pero modifica su lista de argumentos.


Hay muchas maneras de filtrar o seleccionar cosas de una lista usando integradas que son mucho más rápidas que los bucles. El remove-if incorporado se puede usar de esta manera. Por ejemplo, supongamos que quiero soltar los elementos del 3 al 10 en la lista MyList. Ejecute el siguiente código como ejemplo:

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

Obtendrás ''(0 1 2 6 7 8 9).

Supongamos que quiere mantener solo elementos entre 3 y 5. Básicamente, invierte la condición que escribí arriba en el predicado.

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

Obtendrás ''(3 4 5)

Puede usar lo que necesite para el predicado que debe suministrar para eliminar -si. El único límite es tu imaginación sobre qué usar. Puede usar las funciones de filtrado de secuencia, pero no las necesita.

Alternativamente, también puede usar mapcar o mapcar * para pasar por encima de una lista usando alguna función que convierta las entradas específicas en cero y el uso (remove-if nil ...) para eliminar nils.


Si manipula listas en gran medida en su código, utilice la moderna biblioteca de programación funcional dash.el , en lugar de escribir un código repetitivo y reinventar la rueda. Tiene todas las funciones para trabajar con listas, árboles, aplicaciones de función y control de flujo que puedas imaginar. Para mantener todos los elementos que coinciden con un predicado y eliminar otros, necesita un -filter :

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

Otras funciones de interés incluyen -remove , -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)

Lo bueno de dash.el es que admite macros anafóricas . Las macros anafóricas se comportan como funciones, pero permiten una sintaxis especial para hacer que el código sea más conciso. En lugar de proporcionar una función anónima como argumento, simplemente escriba una s-expression y úsela it lugar de una variable local, como x en los ejemplos anteriores. Las macros anafóricas correspondientes comienzan con 2 guiones en lugar de uno:

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