Lisp - 列表



列表一直是傳統 LISP 中最重要和主要的複合資料結構。如今的 Common LISP 提供了其他資料結構,如向量、雜湊表、類或結構體。

列表是單向連結串列。在 LISP 中,列表被構建為一個名為 **cons** 的簡單記錄結構的鏈,這些結構連結在一起。

Cons 記錄結構

**cons** 是一種記錄結構,包含兩個稱為 **car** 和 **cdr** 的元件。

Cons 單元或 cons 是物件,是使用函式 **cons** 建立的一對值。

**cons** 函式接受兩個引數並返回一個新的 cons 單元,其中包含這兩個值。這些值可以是任何型別物件的引用。

如果第二個值不是 nil 或另一個 cons 單元,則這些值將列印為括號括起來的一對點。

cons 單元中的兩個值分別稱為 **car** 和 **cdr**。**car** 函式用於訪問第一個值,**cdr** 函式用於訪問第二個值。

示例

建立一個名為 main.lisp 的新原始碼檔案,並在其中輸入以下程式碼。

main.lisp

; create and print a cons of car 1, cdr 2
(write (cons 1 2))
; terminate printing
(terpri)
; create and print a cons of car a, cdr b
(write (cons 'a 'b))
; terminate printing
(terpri)
; create and print a cons of car 1, cdr nil
(write (cons 1 nil))
; terminate printing
(terpri)
; create and print a cons of car 1, cdr as another cons
(write (cons 1 (cons 2 nil)))
; terminate printing
(terpri)
; create and print multiple cons
(write (cons 1 (cons 2 (cons 3 nil))))
; terminate printing
(terpri)
; create and print multiple cons
(write (cons 'a (cons 'b (cons 'c nil))))
; terminate printing
(terpri)
; create and print multiple cons
(write ( car (cons 'a (cons 'b (cons 'c nil)))))
; terminate printing
(terpri)
; create and print multiple cons
(write ( cdr (cons 'a (cons 'b (cons 'c nil)))))

輸出

執行程式碼時,它將返回以下結果:

(1 . 2)
(A . B)
(1)
(1 2)
(1 2 3)
(A B C)
A
(B C)

上面的示例顯示瞭如何使用 cons 結構來建立單向連結串列,例如,列表 (A B C) 由三個透過它們的 cdr 連結在一起的 cons 單元組成。

LISP 中的列表

雖然可以使用 cons 單元建立列表,但是構建一個由巢狀的 **cons** 函式呼叫組成的列表可能不是最佳解決方案。**list** 函式更常用於在 LISP 中建立列表。

list 函式可以接受任意數量的引數,並且因為它是一個函式,所以它會評估其引數。

**first** 和 **rest** 函式分別給出列表的第一個元素和其餘部分。以下示例演示了這些概念。

示例

更新名為 main.lisp 的原始碼檔案,並在其中輸入以下程式碼。

main.lisp

; create and print a list 
(write (list 1 2))
; terminate printing
(terpri)
; create and print a list 
(write (list 'a 'b))
; terminate printing
(terpri)
; create and print a list 
(write (list 1 nil))
; terminate printing
(terpri)
; create and print a list 
(write (list 1 2 3))
; terminate printing
(terpri)
; create and print a list 
(write (list 'a 'b 'c))
; terminate printing
(terpri)
; create and print a list an car
(write (list 3 4 'a (car '(b . c)) (* 4 -2)))
; terminate printing
(terpri)
; create and print a list of lists
(write (list (list 'a 'b) (list 'c 'd 'e)))

輸出

執行程式碼時,它將返回以下結果:

(1 2)
(A B)
(1 NIL)
(1 2 3)
(A B C)
(3 4 A B -8)
((A B) (C D E))

示例

更新名為 main.lisp 的原始碼檔案,並在其中輸入以下程式碼。

main.lisp

; define a function to return the list
(defun my-library (title author rating availability)
   (list :title title :author author :rating rating :availabilty availability)
)

; call the function and print the result
(write (getf (my-library "Hunger Game" "Collins" 9 t) :title))

輸出

執行程式碼時,它將返回以下結果:

"Hunger Game"

列表操作函式

下表提供了一些常用的列表操作函式。

序號 函式及說明
1

car

它接受一個列表作為引數,並返回其第一個元素。

2

cdr

它接受一個列表作為引數,並返回一個不包含第一個元素的列表。

3

cons

它接受兩個引數,一個元素和一個列表,並返回一個在第一個位置插入該元素的列表。

4

list

它接受任意數量的引數,並返回一個以這些引數作為列表成員元素的列表。

5

append

它將兩個或多個列表合併成一個。

6

last

它接受一個列表並返回一個包含最後一個元素的列表。

7

member

它接受兩個引數,其中第二個引數必須是一個列表,如果第一個引數是第二個引數的成員,則它返回從第一個引數開始的列表的其餘部分。

8

reverse

它接受一個列表並返回一個元素順序相反的列表。

請注意,所有序列函式都適用於列表。

示例

更新名為 main.lisp 的原始碼檔案,並在其中輸入以下程式碼。

main.lisp

; create a car of a sequence
(write (car '(a b c d e f)))
; terminate printing
(terpri)
; create a cdr of a sequence
(write (cdr '(a b c d e f)))
; terminate printing
(terpri)
; create a cons
(write (cons 'a '(b c)))
; terminate printing
(terpri)
; create a list of lists
(write (list 'a '(b c) '(e f)))
; terminate printing
(terpri)
; create a list by appending lists
(write (append '(b c) '(e f) '(p q) '() '(g)))
; terminate printing
(terpri)
; get last car
(write (last '(a b c d (e f))))
; terminate printing
(terpri)
; get reverse of the list
(write (reverse '(a b c d (e f))))

輸出

執行程式碼時,它將返回以下結果:

A
(B C D E F)
(A B C)
(A (B C) (E F))
(B C E F P Q G)
((E F))
((E F) D C B A)

car 和 cdr 函式的連線

**car** 和 **cdr** 函式及其組合允許提取列表的任何特定元素/成員。

但是,car 和 cdr 函式的序列可以透過將字母 a(表示 car)和 d(表示 cdr)連線到字母 c 和 r 中來縮寫。

例如,我們可以編寫 cadadr 來縮寫函式呼叫序列 - car cdr car cdr。

因此,(cadadr '(a (c d) (e f g))) 將返回 d

示例

更新名為 main.lisp 的原始碼檔案,並在其中輸入以下程式碼。

main.lisp

; create a cons from sequences
(write (cadadr '(a (c d) (e f g))))
; terminate printing
(terpri)
; create a cons from a list
(write (caar (list (list 'a 'b) 'c)))   
; terminate printing
(terpri)
; create a cons from a list
(write (cadr (list (list 1 2) (list 3 4))))
; terminate printing
(terpri)

輸出

執行程式碼時,它將返回以下結果:

D
A
(3 4)
廣告