2.5.3. Mapeado sobre Secuencias


LISP provee funciones que procesan secuencialmente los términos de una lista suministrada como argumento.

MAPCAR

(mapcar función lista1 ... listan)
MAPCAR opera sobre los elementos sucesivos de las listas. Primero se aplica la función al CAR de cada lista, entonces al CADR de cada una y así sucesivamente. Lo ideal sería que todas las listas fueran de igual longitud. Si no lo fueran, la iteración concluye al agotarse la lista más corta y los elementos en exceso de las demás listas se ignoran. MAPCAR devuelve una lista con los resultados de las sucesivas llamadas a la función. Por ejemplo:
_1$ (mapcar 'cons '(a b c) '(1 2 3))
((A . 1) (B . 2) (C . 3))
Una expresión-LAMBDA puede ser utilizada con MAPCAR. Esto resulta útil cuando algunos de los argumentos de función son constantes o se proporcionan mediante variables u otros métodos.

Sobre la función MAPCAR seguramente no encontraremos una explicación más entusiasta que la de Vladimir Nemerovski a quien citamos a continuación:

Ahora trataremos de MAPCAR. Esta es una función que requiere:

  1. un símbolo dentro de QUOTE
    o una EXPRESIÓN-LAMBDA (tabién dentro de un QUOTE )
    o una lista de función de usuario (igualmente dentro del QUOTE)
  2. alguna lista
  3. y otras listas opcionales más...

Digamos que la invocamos con (mapcar 'mifunción milista) El resultado será una LISTA de los RESULTADOS de invocar MIFUNCIÓN con cada elemento de MILISTA. Por ejemplo, (defun mysqr(x)(* x x)) (mapcar 'mysqr (list 1 2 3 4)) devolvería (1 4 9 16) De nuevo MYSQR aparece aquí precedida de un apóstrofe (QUOTE), ya que MAPCAR espera que así sea.

MYSQR espera un argumento numérico y eso es lo que obtiene. Si yo la invocara como (MAPCAR 'MYSQR (list 1 2 "3")) LISP intentaría construir una lista de resultados como [1] (list (mysqr 1) (mysqr 2) (mysqr "3")) y yo obtendría un error de BAD ARGUMENT TYPE al intentar procesar el "3". Observe de nuevo que en esta expresión [1], MYSQR es de nuevo un QUOTED-SYM de una función de usuario previamente definida cuyo resultado evalúa como una lista, teniendo también una lista como primer argumento, de manera que en este punto LISP reconoce tal lista como una función de usuario, tratando de evaluarla, sustituyendo los argumentos ficticios de su lista de parámetros por los argumentos reales.

De manera que si usted quiere que alguna función sea usada en MAPCAR y no desea que ésta permanezca por ahí sin ser utilizada de nuevo, usted puede emplear LAMBDA. Esta función crea un tipo de FUNCIÓN ANÓNIMA y la devuelve como encerrada en QUOTE, tal como lo haría DEFUN (sólo que esta crearía una función vinculada a un NOMBRE que de esta manera permanecería formando parte del entorno).

MAPCAR es grandiosa en que no necesita saber cual es la longitud de una lista de datos. No le importa. Simplemente la recorre hasta llegar al final, con lo que lo sabrá en tiempo de ejecución. De manera que usted al escribir la función (que en LISP equivaldría al tiempo de compilación de lenguajes compilados como C, etc.), no necesita saber la longitud exacta de su lista de datos, lo que ¡ES FENOMENAL! Le permite tratar fácilmente con información de longitud variable, y no olvidemos que toda la información real sin duda lo es.

Así que puedo (mapcar 'mysqr '(1 2 3)) o puedo (mapcar 'mysqr '(1 2 3 4 5)), según haga falta.

Y hay algo más. Digamos que tengo esta función que SUMA todos sus argumentos. Es un '+, que puedo invocar como: (+ 1 2) ó (+ 1 2 3) etc.

Ahora cuando escribo (mapcar '+ '(1 2 3) '(4 5 6)) es lo mismo que (list (+ 1 4)(+ 2 5)(+ 3 6)) También puedo escribir (mapcar '+ '(1 2 3)'(4 5 6)'(7 8 9)), que equivale a (list (+ 1 4 7)(+ 2 5 8)(+ 3 6 9)) etc.

De manera que tenemos algo más de flexibilidad aquí. Por supuesto que yo seré el responsable de suministrar a la función invocada con el número adecuado de argumentos que le serán alimentados por MAPCAR, ya que de otra manera obtendré un error de DEMASIADOS/MUY POCOS ARGUMENTOS cuando LISP eventualmente la evalúe.

Fuente:
Subject: A short course in LISP, LAMBDA, QUOTE, MAPCAR...
Date: Sat, 02 Nov 1996 08:50:38 -0800
From: Lu <learly@ix.netcom.com>

VLAX-MAP-COLLECTION

Aplica una función a todos los objetos de una colección.
(vlax-map-collection colección función)
El argumento colección representa un Objeto-VLA de tipo colección. El argumento función será un símbolo o una expresión-LAMBDA que será aplicada a colección.

Ejemplo de utilización de VLAX-MAP-COLLECTION:

Hemos visto anteriormente el desarrolo de una finción que devuelve una lista con los nombres de las capas contenidas en el dibujo utilizando la función VLAX-FOR. Una función similar puede desarrollarse con VLAX-MAP-COLLECTION, con un código resultante aun más claro y conciso. La función que se pasa a VLAX-MAP-COLLECTION se definirá en este caso como una expresión-LAMBDA. Obsérvese que esta expresión debe pasarse dentro de un QUOTE.

;;Función ListaCapas utilizando VLAX-MAP-COLLECTION
;;;Devuelve una lista con los nombres de capas ordenados alfabéticamente
(setq *EsteDibujo* (vla-get-ActiveDocument (vlax-get-acad-object)))
;se ejecuta previamente
(defun ListaCapas (/ ListaCapas objeto-VLA)
(vlax-map-collection
(vlax-get *EsteDibujo* "Layers")
'(lambda (objeto)
(setq ListaCapas (cons (vlax-get objeto "Name") ListaCapas))
) ;_ fin de lambda
) ;_ fin de vlax-map-collection
(acad_strlsort ListaCapas)
) ;_ fin de defun

Su utilización devuelve idénticos resultado que la anterior definida con VLAX-FOR.

Unos ejemplos para concluir...

Conversión de cadena a lista:

Conversión de cadena a lista, con MAPCAR, en una sóla línea. Utilizando esta función podemos convertir al instante cadenas en listas con sus caracteres aislados:

_$ (defun CadenaLista (cadena)(mapcar 'chr (vl-string->list cadena)))
CADENALISTA
_$ (cadenalista "Madrid")
("M" "a" "d" "r" "i" "d")

REMOVE en una sóla línea:

Gracias a Reini Urban hemos podido conocer este brillante ejemplo desarrollado por Sergei Volkov, implementando la función REMOVE (QUITAR) en una sóla línea:

;;;REMOVE, por Segei Volkov
;;;Recibe una expresión
expr y una lista lst.
;;;Devuelve la lista eliminando de ella todas las ocurrencias de la expresión.
;;;Paso 1: Mediante MAPCAR aplica la función LIST a cada término de la lista
;;; Si recibe '(a b c) obtendrá '((a) (b) (c))
;;;Paso 2: Utiliza la función SUBST para sustituir por NIL cada aparición de
;;; la expresión
expr ;;;Paso 3: Aplica mediante APPLY la función APPEND a los miembros de la lista. ;;; de esta manera desaparecen los NIL (listas vacías) que sustituyeron ;;; a la expresión eliminada (defun remove (expr lst) (apply 'append (subst nil (list expr) (mapcar 'list lst))) )

Ejemplo:

_$ (remove 'a '( b c d f a g h j))
(B C D F G H J)
_$
Extracción de los vértices de una Polilínea:

En un capítulo anterior, al estudiar los procesos recursivos, habíamos desarrollado una función destinada a extraer los valores de los vértices de una polilínea. Con los procesos que hemos estudiado hasta ahora pudiéramos intentar el enunciado de una función más concisa y clara para obtener este resultado. A ello dedicaremos el próximo apartado.


Inicio | Índice | Continuar....