2.5.2.2. Iteraciones sobre los Elementos de una Secuencia


FOREACH

Evalúa cada expresión para todos los miembros de una lista
(foreach nombre lista expresión ...)
Recorre la lista, asignando sucesivamente cada elemento de la lista a la variable nombre y evaluando de esta manera cada expresión para cada uno de los elementos de la lista representados por nombre. Puede especificar tantas expresiones como desee. La función FOREACH devuelve el resultado de la última expresión evaluada.

VLAX-FOR

Efectúa una iteración a través de una colección de objetos evaluando cada expresión
(vlax-for símbolo colección [expresión1 [expresión2 ...]])
El argumento símbolo será asignado a cada Objeto-VLA de la colección. El argumento colección representa un objeto ActiveX del tipo colección. [expresión1 [expresión2 ...]] son las expresiones a evaluar. La función devuelve el valor de la última expresión evaluada para el último objeto de la colección.

Ejemplos de iteraciones con FOREACH:

Esta pequeña subrutina, parte de un programa mayor, imprime en pantalla en formato de columna la lista que se le pase como argumento. En el ejemplo se usa para imprimir de manera ordenada la lista de definición deuna entidad polilínea (AutoCAD 2000).

;;;Listado de entidades ;;;Salida por pantalla (defun disp_l (lis_e /) (foreach sublista lis_e (print sublista) ) ;_ fin de foreach (princ) ;evita la repetición de la última línea ) ;_ fin de defun

Command: (entget(car(entsel))) Select object: ((-1 . <Entity name: 1487558>) (0 . "LWPOLYLINE") (330 . <Entity name: 14874f8>) (5 . "2B") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "0") (100 . "AcDbPolyline") (90 . 4) (70 . 0) (43 . 0.0) (38 . 0.0) (39 . 0.0) (10 99.3432 134.975) (40 . 0.0) (41 . 0.0) (42 . 0.0) (10 130.202 185.828) (40 . 0.0) (41 . 0.0) (42 . 0.0) (10 202.747 163.648) (40 . 0.0) (41 . 0.0) (42 . 0.0) (10 269.336 215.041) (40 . 0.0) (41 . 0.0) (42 . 0.0) (210 0.0 0.0 1.0))


La lista impresa en pantalla resulta difícil de leer, al no estar ordenada en columna

Command: (disp_l (entget(car(entsel)))) (-1 . <Entity name: 1487558>) (0 . "LWPOLYLINE") (330 . <Entity name: 14874f8>) (5 . "2B") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "0") (100 . "AcDbPolyline") (90 . 4) (70 . 0) (43 . 0.0) (38 . 0.0) (39 . 0.0) (10 99.3432 134.975) (40 . 0.0) (41 . 0.0) (42 . 0.0) (10 130.202 185.828) (40 . 0.0) (41 . 0.0) (42 . 0.0) (10 202.747 163.648) (40 . 0.0) (41 . 0.0) (42 . 0.0) (10 269.336 215.041) (40 . 0.0) (41 . 0.0) (42 . 0.0) (210 0.0 0.0 1.0)

Ejemplos de iteraciones con VLAX-FOR:

LISTADO DE CAPAS

Considerado desde el punto de vista de la jerarquía de objetos ActiveX a la que podemos acceder con Visual LISP,

AutoCAD y sus dibujos consisten en muchos objetos diferentes tales como tipos de líneas, capas, bloques, etc. Estos objetos se agrupan en colecciones. Las colecciones de Bloques (Block), Grupos (Group), Conjuntos de Selección (SelectionSet), EspacioModelo (ModelSpace) y EspacioPapel (PaperSpace) pueden contener una variedad de objetos gráficos diferentes, tales como líneas, arcos, texto, etc. Todas las demás colecciones contienen objetos de un sólo tipo.
Las colecciones AutoCAD son de base cero, es decir que se enumeran a partir de cero en sentido ascendente. Algunas colecciones poseen objetos de manera automática. Por ejemplo, la colección Layers (capas) simpre contiene un objeto capa de nombre "0", mientras que otras se encuentran vacías inicialmente.
Sutphin, J. AutoCAD 2000 VBA Programmers Reference, pág 47.

La rutina que exponemos a continuación extrae los nombres de las capas de un dibujo aplicando la función VLAX-FOR a la colección "Layers". Para obtener la colección "Layers" tenemos que recorrer la jerarquía de objetos, a partir del único objeto accesible públicamente que es el objeto "Application" (Aplicación). La secuencia a seguir es la siguiente:

  1. Obtener el objeto "Aplicación": (vlax-get-acad-object)
  2. Obtener el objeto "Documento Activo" es decir, el dibujo en que se trabaja: (vla-get-ActiveDocument (vlax-get-acad-object))
    En caso de que se vaya a hacer referencia a este objeto en múltiples ocasiones, sería conveniente extraerlo una sóla vez y guardarlo en una variable global:
    (setq *EsteDibujo* (vla-get-ActiveDocument (vlax-get-acad-object)))
    Esta línea la situamos fuera del defun. Se ejecutaría al cargar el programa.
  3. Obtener la colección "Layers" (Capas): (vlax-get *EsteDibujo* "Layers" )

Una vez obtenida la colección de capas se aplica mediante VLAX-FOR a cada objeto-VLA de dicha colección la función
(setq ListaCapas (cons (vlax-get objeto-VLA "Name") *ListaCapas*))
Aquí primero extraemos el nombre de la capa. El nombre de cada objeto "Layer" se encuentra en la propiedad "Name" y se puede extraer mediante (vlax-get objeto-VLA "Name"). Una vez obtenido el nombre de la capa, la incluimos mediante CONS en una variable local ListaCapas. Esta lista contendrá al terminar el ciclo de VLAX-FOR los nombres de todas las capas del dibujo activo. Ya para terminar, ordenamos la lista de capas mediante la función ACAD_STRLSORT. Esta lista serviría, por ejemplo para llenar una casilla de lista en un cuadro de diálogo creado mediante el lenguaje DCL.

;;;Función ListaCapas ;;;Devuelve una lista con los nombres de capas ordenados alfabéticamente ;;;Obsérvese la posibilidad aquí demostrada de tener una función y una variable ;;;con idéntico nombre en un mismo entorno. Para ello será necesario que dicha ;;;variable, en este caso ListaCapas sea una variable local de la función.
(setq *EsteDibujo* (vla-get-ActiveDocument (vlax-get-acad-object))) ;se ejecuta previamente
(defun ListaCapas (/ ListaCapas) (vlax-for objeto-VLA (vlax-get *EsteDibujo* "Layers") (setq ListaCapas (cons (vlax-get objeto-VLA "Name") ListaCapas)) ;el mismo nombre se utiliza para la variable local que guarda ;temporalmente el listado de capas. ) ;_ fin de vlax-for (acad_strlsort ListaCapas) ) ;_ fin de defun

Ejemplo de su utilización:

Command: (LOAD "C:/Mis documentos/Lisp/Fuentes/ListaCapas.lsp") LISTACAPAS Command: !*EsteDibujo* <#VLA-OBJECT IAcadDocument 00eb6aa4> Command: (listaCapas) ("0" "DEFPOINTS" "DOTACIONES" "IT" "RBA" "RE-2" "RI" "RI-1" "RIA" "SG-EL" "SG-M" "SGP")

Más adelante se estudiará en más detalle el acceso a los objetos ActiveX desde Visual LISP.

Unos ejemplos para concluir...

Como ejemplo del empleo dentro de AutoCAD de estas últimas funciones estudiadas, aquí van algunas pequeñas utilidades creadas por Vladimir Nesterovsky. La primera de ellas, SEL2LST crea una lista de nombres de entidad a partir de un conjunto de selección. La segunda, LST2SEL, realiza el proceso inverso, creando un conjunto de selección a partir de una lista de nombres de entidad:

;;;SEL2LST ;;;Recibe un conjunto de selección y devuelve una lista (defun sel2lst( sel / n l) (repeat (setq n (sslength sel)) (setq n (1- n) l (cons (ssname ss n) l)) ) )

;;;LST2SEL ;;;La función opuesta, recibe una lista y devuelve un conjunto de selección (defun lst2sel(l / ss) (setq ss (ssadd)) (foreach e l (ssadd e ss)) )

La siguiente función extrae el resto de una lista l a partir del término n indicado en el primer argumento:

(defun cdnr ( n l ) (repeat n (setq l (cdr l)) ) )

La función STRTOL recibe una cadena de caracteres s y devuelve los caracteres aislados (cadenas de un sólo carácter) agrupados en una lista:

(defun strtol ( s / lst c ) (repeat (setq c (strlen s)) (setq lst (cons (substr s c 1) lst) c (1- c) ) ) lst )

Como se ve, esta puede ser otra vía para abordar el desarrollo del predicado PALINDROMOP: obtener mediante STRTOL la cadena de caracteres en forma de lista y entonces compararla con la lista invertida por reverse:

(defun palindromop (cadena) (setq cadena (strtol cadena)) (equal cadena (reverse cadena)) )
;; Created by Vladimir Nesterovsky 
;; YOU MAY USE THIS FUNCTION AS IT IS FOR ANY PURPOSE
;; AT YOUR OWN RISK IF YOU RETAIN THIS NOTICE COMPLETE 
;; AND UNALTERED. NO WARRANTIES GIVEN WHATSOEVER.

Inicio | Índice | Continuar...
Comments