Skip to main content

list-length

list-length Function

Syntax:

list-length list → length

Arguments and Values:

list—a proper list or a circular list.

length—a non-negative integer , or nil.

Description:

Returns the length of list if list is a proper list. Returns nil if list is a circular list.

Examples:

(list-length(a b c d))4 
(list-length(a (b c) d))3
(list-length())0
(list-length nil)0
(defun circular-list (&rest elements)
(let ((cycle (copy-list elements)))
(nconc cycle cycle)))
(list-length (circular-list ’a ’b)) → NIL
(list-length (circular-list ’a)) → NIL
(list-length (circular-list))0

Exceptional Situations:

Should signal an error of type type-error if list is not a proper list or a circular list.

See Also:

length

Notes:

list-length could be implemented as follows:

(defun list-length (x)

(do ((n 0 (+ n 2)) ;Counter.

(fast x (cddr fast)) ;Fast pointer: leaps by 2.

(slow x (cdr slow))) ;Slow pointer: leaps by 1.

(nil)

;; If fast pointer hits the end, return the count.

(when (endp fast) (return n))

(when (endp (cdr fast)) (return (+ n 1)))

;; If fast pointer eventually equals slow pointer,

;; then we must be stuck in a circular list.

;; (A deeper property is the converse: if we are

;; stuck in a circular list, then eventually the

;; fast pointer will equal the slow pointer.

;; That fact justifies this implementation.)

(when (and (eq fast slow) (> n 0)) (return nil))))

Expanded Reference: list-length

Basic usage

list-length returns the length of a proper list, similar to length.

(list-length '(a b c d))
=> 4

(list-length '(1 (2 3) 4))
=> 3

(list-length '())
=> 0

Detecting circular lists

Unlike length, list-length returns NIL for circular lists instead of looping forever.

(let ((lst (list 1 2 3)))
(setf (cdr (last lst)) lst) ; make it circular
(list-length lst))
=> NIL

Circular list of one element

(let ((lst (list 'a)))
(setf (cdr lst) lst) ; circular: (a a a ...)
(list-length lst))
=> NIL

Comparison with length

list-length is safe for circular lists, while length would loop indefinitely. For proper lists, they return the same value.

(let ((lst '(x y z)))
(values (list-length lst)
(length lst)))
=> 3
=> 3

Practical use: safe list length check

(defun safe-list-p (x)
"Returns T if x is a proper list (not circular)."
(and (listp x)
(not (null (list-length x)))))

(safe-list-p '(1 2 3))
=> T

(safe-list-p nil)
=> T