AutoLISP: The Complete Guide — Chapter 8 / 16

Lists

The name LISP stands for LISt Processing. Lists are the fundamental data structure of the language. Everything in LISP is built around lists: data, programs, and even function definitions. Understanding lists means understanding LISP.

Creating lists

With the list function

The most common way to create a list:

(list 1 2 3)              ; → (1 2 3)
(list "a" "b" "c")        ; → ("a" "b" "c")
(list 10.0 20.0 0.0)      ; → (10.0 20.0 0.0) — a 3D point!

The elements of a list can be of different types:

(list "AutoCAD" 2025 3.14 T)  ; → ("AutoCAD" 2025 3.14 T)

With the apostrophe ' (quote)

The apostrophe is a shortcut for creating lists of literal values:

'(1 2 3)           ; → (1 2 3)
'("a" "b" "c")     ; → ("a" "b" "c")

Warning: the apostrophe prevents evaluation. With list, arguments are evaluated:

(setq x 5)
(list x 10)   ; → (5 10) — x is evaluated to 5
'(x 10)       ; → (X 10) — x is NOT evaluated, it's the symbol X

Use list when your elements contain variables or expressions, and ' when you have constant values.

Difference between list and quote

Accessing elements

car: the first element

(car '(1 2 3))      ; → 1
(car '("a" "b"))     ; → "a"

cdr: the rest of the list (everything except the first)

(cdr '(1 2 3))      ; → (2 3)
(cdr '("a" "b"))     ; → ("b")
(cdr '(1))           ; → nil (empty list)

Why car and cdr?

These names come from the architecture of the IBM 704 computer on which LISP was created in 1958. car stands for Contents of the Address Register and cdr for Contents of the Decrement Register. These names have stuck by tradition, even though nobody programs on an IBM 704 anymore!

IBM 704

Lawrence Livermore National Laboratory, Attribution, via Wikimedia Commons

nth: access by index

To directly access an element by its position (starting at 0):

(nth 0 '(10 20 30))   ; → 10
(nth 1 '(10 20 30))   ; → 20
(nth 2 '(10 20 30))   ; → 30

last: the last element

(last '(1 2 3))      ; → 3

length: number of elements

(length '(1 2 3))     ; → 3
(length '())           ; → 0
(length nil)           ; → 0

Combinations of car and cdr

AutoLISP provides shortcuts for common combinations:

(cadr '(1 2 3))     ; → 2 — equivalent to (car (cdr '(1 2 3)))
(caddr '(1 2 3))    ; → 3 — equivalent to (car (cdr (cdr '(1 2 3))))
(cddr '(1 2 3))     ; → (3)

In CAD, these combinations are ubiquitous because points are lists of coordinates:

(setq point '(10.0 20.0 5.0))

(car point)    ; → 10.0 (X coordinate)
(cadr point)   ; → 20.0 (Y coordinate)
(caddr point)  ; → 5.0  (Z coordinate)

Personally, I prefer using nth to access a point's coordinates — it's more immediately readable:

(nth 0 point)  ; → 10.0 (X coordinate)
(nth 1 point)  ; → 20.0 (Y coordinate)
(nth 2 point)  ; → 5.0  (Z coordinate)

Building and modifying lists

cons: add to the beginning

cons adds an element at the head of a list:

(cons 0 '(1 2 3))     ; → (0 1 2 3)
(cons "x" '("a" "b")) ; → ("x" "a" "b")

Technically, cons creates a dotted pair — a cell that contains exactly two values. If the second argument is a list, the result is a normal list (the pair points to the rest of the chain). Otherwise, the result is a dotted pair, indicated by a dot between the two elements:

(cons 1 2)             ; → (1 . 2) — dotted pair
(cons 1 '(2 3))        ; → (1 2 3) — list

The dot . is not an operator — it's how AutoLISP displays a pair whose second element is not a list. You can also write a literal dotted pair using the quoted syntax:

'(8 . "MyLayer")       ; Dotted pair: key 8, value "MyLayer"

Don't confuse a dotted pair with a two-element list:

'(8 . "MyLayer")       ; → (8 . "MyLayer") — dotted pair (2 values in 1 cell)
'(8 "MyLayer")         ; → (8 "MyLayer")   — list of 2 elements (2 chained cells)

The difference matters when using car and cdr:

;; On a dotted pair
(car '(8 . "MyLayer"))   ; → 8
(cdr '(8 . "MyLayer"))   ; → "MyLayer" (the value directly)

;; On a list
(car '(8 "MyLayer"))     ; → 8
(cdr '(8 "MyLayer"))     ; → ("MyLayer") (a list containing the value)

With a dotted pair, cdr returns the value directly. With a list, cdr returns a list. This is why dotted pairs are preferred in AutoCAD entity association lists: they allow you to extract the value with a simple cdr, without needing an additional car. We'll come back to this in the next section.

append: concatenate lists

(append '(1 2) '(3 4))       ; → (1 2 3 4)
(append '("a") '("b") '("c")) ; → ("a" "b" "c")

reverse: reverse a list

(reverse '(1 2 3))   ; → (3 2 1)

Traversing a list

With foreach

foreach is the simplest way to traverse a list:

(foreach element '("AutoCAD" "Inventor" "Revit")
  (princ (strcat "\nProduct: " element))
)

Result:

Product: AutoCAD
Product: Inventor
Product: Revit

foreach result

With while and cdr

The classic technique for traversing a list in LISP:

(setq mylist '(10 20 30 40 50))

(while mylist
  (princ (strcat "\nElement: " (itoa (car mylist))))
  (setq mylist (cdr mylist))
)

At each iteration, car extracts the first element and cdr reduces the list. When the list is empty (nil), the loop stops.

Association lists

Association lists (alists) are a very common pattern in AutoLISP. They are the LISP equivalent of a Dictionary in C#/.NET or a dict in Python: a structure that maps keys to values. Each element is a dotted pair (key . value):

(setq person
  (list
    (cons 0 "John")
    (cons 1 35)
    (cons 2 "Engineer")
  )
)
;; → ((0 . "John") (1 . 35) (2 . "Engineer"))

assoc: look up by key

(assoc 0 person)   ; → (0 . "John")
(assoc 1 person)   ; → (1 . 35)
(assoc 9 person)   ; → nil (key not found)

To get just the value:

(cdr (assoc 0 person))  ; → "John"

Association lists in AutoCAD

This is exactly the format AutoLISP uses to represent AutoCAD entities. Each entity is an association list where DXF codes serve as keys:

;; Select the last drawn entity and read its data
(setq data (entget (entlast)))

The result looks like this:

((-1 . <Entity name: ...>)
 (0 . "LINE")
 (10 1.0 2.0 0.0)
 (11 5.0 8.0 0.0)
 ...)
  • Code 0 contains the entity type ("LINE", "CIRCLE", etc.)
  • Code 10 contains the start point
  • Code 11 contains the end point

Practical example: analyzing a selection

(defun c:count-types (/ selection index entity entity-type counter)
  (setq selection (ssget))  ; Prompt for a selection
  (if selection
    (progn
      (setq counter '())
      (setq index 0)
      (repeat (sslength selection)
        (setq entity (ssname selection index))
        (setq entity-type (cdr (assoc 0 (entget entity))))

        ;; Check if this type already exists in the counter
        (if (assoc entity-type counter)
          (setq counter
            (subst
              (cons entity-type (1+ (cdr (assoc entity-type counter))))
              (assoc entity-type counter)
              counter
            )
          )
          (setq counter (cons (cons entity-type 1) counter))
        )
        (setq index (1+ index))
      )

      ;; Display the results
      (foreach pair counter
        (princ (strcat "\n" (car pair) " : " (itoa (cdr pair))))
      )
    )
    (princ "\nNo selection.")
  )
  (princ)
)

This program counts entities by type in a selection. Don't worry if some functions (ssget, sslength, ssname, entget, subst, 1+) are new — the goal here is to see how association lists are used in a real-world context.

Summary

Function Purpose Example
list Create a list (list 1 2 3)(1 2 3)
' Literal list '(1 2 3)(1 2 3)
car First element (car '(1 2 3))1
cdr Rest of the list (cdr '(1 2 3))(2 3)
nth Element by index (nth 1 '(1 2 3))2
last Last element (last '(1 2 3))3
length Number of elements (length '(1 2 3))3
cons Add to front (cons 0 '(1 2))(0 1 2)
append Concatenate (append '(1) '(2))(1 2)
reverse Reverse (reverse '(1 2 3))(3 2 1)
foreach Traverse (foreach x lst ...)
assoc Look up by key (assoc 0 alist)

In the next chapter, we'll see how to interact with the user: asking them to click a point, enter a number or text, using AutoLISP's get* functions.


Helping hand Need an AutoCAD (AutoLISP, ObjectARX, .NET, VBA) development? Contact me for a free quote.