LISP - 集合(Set)

  • 简述

    Common Lisp 不提供集合数据类型。但是,它提供了许多允许在列表上执行集合操作的函数。
    您可以根据各种条件添加、删除和搜索列表中的项目。您还可以执行各种集合操作,例如:并集、交集和集差。
  • 在 LISP 中实现集合

    集合,就像列表一样,通常是根据 cons cells 来实现的。然而,正是由于这个原因,集合越大,集合操作的效率就越低。
    adjoin功能允许您建立一个集合。它接受一个项目和一个表示集合的列表,并返回一个列表,该列表表示包含该项目和原始集中所有项目的集合。
    adjoin函数首先查找给定列表中的项目,如果找到,则返回原始列表;否则它会创建一个新的cons cellcar作为项目和cdr指向原始列表并返回这个新列表。
    adjoin功能也需要:key:test关键字参数。些参数用于检查项目是否存在于原始列表中。
    由于 adjoin 函数不修改原始列表,要对列表本身进行更改,您必须将 adjoin 返回的值分配给原始列表,或者您可以使用宏pushnew将项目添加到集合中。

    例子

    创建一个名为 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 函数组允许你检查一个元素是否是一个集合的成员。
    以下是些函数的语法 -
    
    member item list &key :test :test-not :key 
    member-if predicate list &key :key 
    member-if-not predicate list &key :key
    
    些函数在给定列表中搜索满足测试的给定项目。如果没有找到样的项目,则函数返回nil.否则,返回以该元素为第一个元素的列表的尾部。
    搜索仅在顶级进行。
    些函数可以用作谓词。

    例子

    创建一个名为 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函数执行相同的操作,但可能会破坏参数列表。

    例子

    创建一个名为 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三个向量列表的参数。是因为,列表是由 cons 单元格组成的,尽管些值在我们看来显然是一样的,但cdr部分单元格不匹配,因此它们与 LISP 解释器/编译器不完全相同。就是原因;不建议使用列表来实现大集合。虽然它适用于小型设备。
  • 设置交叉口

    函数的交集组允许您在测试的基础上对作为些函数的参数提供的两个列表执行交集。
    以下是些函数的语法 -
    
    intersection list1 list2 &key :test :test-not :key 
    nintersection list1 list2 &key :test :test-not :key
    
    些函数接受两个列表并返回一个新列表,其中包含两个参数列表中存在的所有元素。如果任一列表具有重复条目,则冗余条目可能会或可能不会出现在结果中。

    例子

    创建一个名为 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 函数返回第一个列表中没有出现在第二个列表中的元素列表。

    例子

    创建一个名为 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))