AfraLISP - Learn AutoLISP for AutoCAD productivity

List Manipulation

by Kenny Ramage

List Manipulation - Part 1

As you are probably well aware, LISP stands for "List Processing".
(Not "Lost in Stupid Parenthesis")

A list is a group of elements consisting of any data type and is stored as a single variable. A list can contain any number of Reals, Integers, Strings, Variables and even other Lists.

Let's have a look at a list. Type this :

	(setq pt1 (getpoint "\nChoose a Point : "))

AutoLisp should return something like this :

	(127.34 35.23 0.0)

Fine, you say, I've got a list but what do I do with it?
AutoLisp has many functions available to manipulate lists.
Let's have a look at them.

Car

The primary command for taking a list apart is the "Car" function. This function returns the first element of a list. (The x coordinate.)

For example :

	(setq a (car pt1))

Would return :

	(127.34)

Cdr

This function returns the second element plus the remaining elements of a list. For example :

	(setq b (cdr pt1))

Would return :

	(35.23 0.0)

But what if we only wanted the second element? We could write :

	(setq b (car (cdr pt1)))

But there is a better way. AutoLisp has provided the "Cadr" function which is basically an abbreviation of a nested command.

Cadr

This returns the second element of a list. (The y coordinate)

	(setq b (cadr pt1))

This would return :

	(35.23)

Likewise, there is another abbreviated function to return the third element.

Caddr

This returns the third element of a list. (The z coordinate)

	(setq c (caddr pt1))

Would return :

	(0.0)

AutoLisp has other functions that will retrieve values from lists of more than three elements. (Caar, cadar, etc). You can, though, us another function to access any element of a list. This is the "nth" function.

nth

The syntax for the nth function is as follows :

	(nth num list)

"num" is the number of the element to return. Just remember that zero is the first element. For example given the list :

	(setq d '("M10" "M20" "M30" 10.25))
	(setq e (nth 0 d))

Would return :

	("M10")

And likewise :

	(setq f (nth 3 d))

Would return :

	(10.25)

In part 2 we will look at a practical example of using these functions.

List Manipulation - Part 2

We've now managed to extract elements from a list, but what do you do if you want to create a new list. Let's say you have two elements :

	(setq a 200.0)
	(setq b 400.0)

You want to combine them to create a new list. To do this you would use the "List" function. For example :

	(setq c (list a b))

Would return :

	(200.0 400.0)

You could also write the function like this :

	(setq c '(a b))

Here's an example of List Manipulation. We are going to use the (car), (cadr) and (list) function to draw a rectangle.

(defun c:rec ( / pt1 pt2 pt3 pt4)
 
	(setq pt1 (getpoint "\nSelect First Corner: "))
	;get the first point
 
	(setq pt3 (getcorner pt1 "\nSelect Second Corner: "))
	;get the third point
 
	(setq pt2 (list (car pt1) (cadr pt3)))
	;construct the second point
 
	(setq pt4 (list (car pt3) (cadr pt1)))
	;construct the fourth point
 
	(command "Line" pt1 pt2 pt3 pt4 "c")
	;draw the rectangle
 
  (princ)
 
);defun
;**********************************************************

Let's look closer at the line :

	(setq pt2 (list (car pt1) (cadr pt3)))

This function retrieves the first element (x coordinate) from the list pt1, the second element (y coordinate) from the list pt3, creates a list from these elements and stores the list in the variable pt2.

The following diagram should help you to better understand this.

Rectangle

AutoLisp provides other functions to manipulate lists. Let's have a look at some of them.

Append

This takes any number of lists and runs them together as one list :

	(append '(12.0 15.5) '("M20" "M30))

Would return :

	(12.0 15.5 "M20" "M30")

Last

Will return the last element of a list :

	(last '("M20" "M24" "M30"))

Would return :

	("M30")

Length

This returns an integer indicating the number of elements in a list :

	(length '("M20" "M24" "M30"))

Would return :

	(3)

Member

This function searches a list for a specific element. If found it returns the element plus the remainder of the list :

	(member 'c '(a b c d e f))

Would return :

	(c d e f)

Reverse

Returns a list with it's elements reversed :

	(reverse '(a b c d e f))

Would return :

	(f e d c b a)

Subst

Searches a list for an old element and returns a copy of the list with the new item substituted in place of every occurrence of the old item :

	Syntax : (subst newitem olditem lst)
 
	(setq lst '(a b c d e c)))
 
	(subst 'f 'c lst)

Would return :

	(a b f d e f)

In part 3 we will have a look at a more advanced List Manipulation Example.

List Manipulation - Part 3

It is good practice (and manners) when writing Lisp routines to restore the system environment to the state that your program found it in on completion of your application. Most AutoLisp routines start and end like this :

(defun c:example ()
	(setq oldhigh (getvar "Highlight")
	      oldsnap (getvar "Osmode")
	      oldblip (getvar "BlipMode")
	      oldecho (getvar "Cmdecho")
	);setq
 
	(setvar "Highlight" 0)
	(setvar "Osmode" 517)
	(setvar "Blipmode" 0)
	(setvar "Cmdecho" 0)
 
	Programme statements.............
	.................................
 
	(setvar "Highlight" oldhigh)
	(setvar "Osmode" oldsnap)
	(setvar "Blipmode "oldblip)
	(setvar "Cmdecho" oldecho)
  (princ)
);defun
;******************************************************

I must have written statements like this a thousand times in my Lisp routines.

The following example is designed to act as a global routine that first stores, then changes specific system variables. On completion of the routine, the function is then called again and all system variables are returned to their previous settings.

(defun varget ()
 
	(setq lis '("HIGHLIGHT" "BLIPMODE" "CMDECHO"
		    "BLIPMODE" "OSMODE"))
	;store names of system variables
 
	(setq  var (mapcar 'getvar lis))
	;get the value of the system variables and
	;store them as a list
 
	(setq var1 '(0 0 0 0 517))
	;store the new values of the system variables
 
	(setq no 0)
	;set counter to zero
 
	(repeat (length lis)
	;get the number of variables in the list
	;to use as the counter control number
 
		(setvar (nth no lis) (nth no var1))
		;set the variables to their new values
 
		(setq no (1+ no))
		;move up one in the list
 
	);repeat
 
  (princ);finish quietly
 
);defun
 
;***************************************************************
 
(defun varset ()
 
	(setq no 0)
	;set counter to zero
 
	(repeat (length lis)
	;get the number of variables in the list
 
		(setvar (nth no lis) (nth no var))
		;reset the variables to their original values
 
		(setq no (1+ no))
		;move up one in the list
 
	);repeat
 
  (princ);finish quietly
 
);defun
 
;***************************************************************
 
(princ);load quietly

Our Autolisp routine could now look like this :

(defun c:example ()
 
	(varget)
	;store system variables and then reset them
 
	Programme statements.............
	.................................
 
	(varset)
	;restore system variables
 
  (princ)
);defun
;******************************************************

As you can see, we have reduced the size of our routine by a lot and saved ourselves quite a bit of typing. These two routines could both be loaded from our Acad.Lsp file so that they would be available to all of your routines.

If you would like the source coding for this AutoLisp Tutorial then Click Here. Ta Ta for Now…