当前位置: 首页 > 文档资料 > LISP 中文教程 >

Set

优质
小牛编辑
138浏览
2023-12-01

Common Lisp不提供set数据类型。 但是,它提供了许多允许在列表上执行集合操作的功能。

您可以根据各种条件添加,删除和搜索列表中的项目。 您还可以执行各种设置操作,例如:union,intersection和set difference。

在LISP中实现集合

像列表一样的集合通常根据cons单元格来实现。 但是,由于这个原因,集合获得的集合越大,效率越低。

adjoin函数允许您构建一个集合。 它接受一个项目和一个表示集合的列表,并返回一个列表,该列表表示包含该项目的集合以及原始集合中的所有项目。

adjoin函数首先查找给定列表中的项目,如果找到,则返回原始列表; 否则它会创建一个新的cons单元格,其car作为项目, cdr指向原始列表并返回此新列表。

adjoin函数还包括:key:test关键字参数。 这些参数用于检查项目是否存在于原始列表中。

由于adjoin函数不修改原始列表,要在列表本身中进行更改,您必须将pushnew返回的值分配给原始列表,或者,您可以使用宏pushnew将项添加到集合中。

例子 (Example)

创建一个名为main.lisp的新源代码文件,并在其中键入以下代码。

; creating myset as an empty list
(defparameter *myset* ())
(adjoin 1 *myset*)
(adjoin 2 *myset*)
; adjoin did not change the original set
;so it remains same
(write *myset*)
(terpri)
(setf *myset* (adjoin 1 *myset*))
(setf *myset* (adjoin 2 *myset*))
;now the original set is changed
(write *myset*)
(terpri)
;adding an existing value
(pushnew 2 *myset*)
;no duplicate allowed
(write *myset*)
(terpri)
;pushing a new value
(pushnew 3 *myset*)
(write *myset*)
(terpri)

执行代码时,它返回以下结果 -

NIL
(2 1)
(2 1)
(3 2 1)

检查会员资格

成员函数组允许您检查元素是否是集合的成员。

以下是这些函数的语法 -

member item list &key :test :test-not :key 
member-if predicate list &key :key 
member-if-not predicate list &key :key

这些函数在给定列表中搜索满足测试的给定项。 如果找不到这样的项,则函数返回nil. 否则,返回以元素作为第一个元素的列表尾部。

搜索仅在顶级进行。

这些函数可以用作谓词。

例子 (Example)

创建一个名为main.lisp的新源代码文件,并在其中键入以下代码。

(write (member 'zara '(ayan abdul zara riyan nuha)))
(terpri)
(write (member-if #'evenp '(3 7 2 5/3 'a)))
(terpri)
(write (member-if-not #'numberp '(3 7 2 5/3 'a 'b 'c)))

执行代码时,它返回以下结果 -

(ZARA RIYAN NUHA)
(2 5/3 'A)
('A 'B 'C)

设置联盟

联合函数组允许您在两个列表上执行集合,这两个列表作为参数提供,作为测试的基础。

以下是这些函数的语法 -

union list1 list2 &key :test :test-not :key 
nunion list1 list2 &key :test :test-not :key

union函数接受两个列表并返回一个新列表,其中包含任一列表中的所有元素。 如果存在重复,则只有该成员的一个副本保留在返回的列表中。

nunion函数执行相同的操作,但可能会破坏参数列表。

例子 (Example)

创建一个名为main.lisp的新源代码文件,并在其中键入以下代码。

(setq set1 (union '(a b c) '(c d e)))
(setq set2 (union '(#(a b) #(5 6 7) #(f h)) 
   '(#(5 6 7) #(a b) #(g h)) :test-not #'mismatch)
)
(setq set3 (union '(#(a b) #(5 6 7) #(f h)) 
   '(#(5 6 7) #(a b) #(g h)))
)
(write set1)
(terpri)
(write set2)
(terpri)
(write set3)

执行代码时,它返回以下结果 -

(A B C D E)
(#(F H) #(5 6 7) #(A B) #(G H))
(#(A B) #(5 6 7) #(F H) #(5 6 7) #(A B) #(G H))

请注意

如果没有:test-not #'mismatch union :test-not #'mismatch三个向量列表的参数,union函数将无法正常工作。 这是因为,列表由cons单元组成,虽然值看起来与我们看起来相同,但是单元格的cdr部分不匹配,因此它们与LISP解释器/编译器不完全相同。 这就是原因; 不建议使用列表来实现大集合。 它适用于小型套装。

设置交叉点

交集的函数组允许您在两个列表上执行交集,这些列表作为参数提供,作为测试的基础。

以下是这些函数的语法 -

intersection list1 list2 &key :test :test-not :key 
nintersection list1 list2 &key :test :test-not :key

这些函数采用两个列表并返回一个新列表,其中包含两个参数列表中的所有元素。 如果任一列表具有重复条目,则冗余条目可能会也可能不会出现在结果中。

例子 (Example)

创建一个名为main.lisp的新源代码文件,并在其中键入以下代码。

(setq set1 (intersection '(a b c) '(c d e)))
(setq set2 (intersection '(#(a b) #(5 6 7) #(f h)) 
   '(#(5 6 7) #(a b) #(g h)) :test-not #'mismatch)
)
(setq set3 (intersection '(#(a b) #(5 6 7) #(f h)) 
   '(#(5 6 7) #(a b) #(g h)))
)
(write set1)
(terpri)
(write set2)
(terpri)
(write set3)

执行代码时,它返回以下结果 -

(C)
(#(A B) #(5 6 7))
NIL

交集函数是交集的破坏性版本,即它可能破坏原始列表。

设定差异

set-difference函数组允许您在基于测试的两个列表上执行设置差异,这两个列表作为这些函数的参数提供。

以下是这些函数的语法 -

set-difference list1 list2 &key :test :test-not :key 
nset-difference list1 list2 &key :test :test-not :key

set-difference函数返回第一个列表中未出现在第二个列表中的元素列表。

例子 (Example)

创建一个名为main.lisp的新源代码文件,并在其中键入以下代码。

(setq set1 (set-difference '(a b c) '(c d e)))
(setq set2 (set-difference '(#(a b) #(5 6 7) #(f h)) 
   '(#(5 6 7) #(a b) #(g h)) :test-not #'mismatch)
)
(setq set3 (set-difference '(#(a b) #(5 6 7) #(f h)) 
   '(#(5 6 7) #(a b) #(g h)))
)
(write set1)
(terpri)
(write set2)
(terpri)
(write set3)

执行代码时,它返回以下结果 -

(A B)
(#(F H))
(#(A B) #(5 6 7) #(F H))