Common Lisp是否具有类似于Java的Set Interface / implementing类的东西?
我需要这样的东西,一个元素集合,其中不包含任何元素的重复项。 Common Lisp,特别是SBCL,有这样的东西吗?
解决方案
并不是我所知道的,但是我们可以将散列表用于类似的东西。
Lisp哈希表基于CLOS。规格在这里。
对于快速解决方案,只需使用哈希表(如前所述)即可。
但是,如果我们喜欢更原则的方法,则可以看一下FSet,它是一个功能强大的集合理论集合库。除其他外,它包含套件和袋子的类和操作。
(编辑:)最干净的方法可能是将面向集合的操作定义为泛型函数。毕竟,一组通用函数基本上等效于Java接口。我们可以简单地在标准HASH-TABLE类上实现方法作为第一个原型,并允许其他实现。
我们可以使用列表,尽管它们可能无法有效地表示大型集合。使用ADJOIN或者PUSHNEW将新元素添加到列表中,然后使用DELETE或者REMOVE进行相反操作即可完成此操作。
(let ((set (list)))
(pushnew 11 set)
(pushnew 42 set)
(pushnew 11 set)
(print set) ; set={42,11}
(setq set (delete 42 set))
(print set)) ; set={11}
需要注意的一件事是,这些运算符默认情况下全部使用EQL来测试集合中可能存在的重复项(就像Java使用equals方法一样)。这对于包含数字或者字符的集合是可以的,但是对于其他对象的集合,应将诸如" EQUAL"之类的"更深"相等性测试指定为:TEST关键字参数,例如对于一组字符串:-
(let ((set (list)))
(pushnew "foo" set :test #'equal)
(pushnew "bar" set :test #'equal)
(pushnew "foo" set :test #'equal) ; EQUAL decides that "foo"="foo"
(print set)) ; set={"bar","foo"}
Lisp与Java的Set操作相对应的是:
- addAll-> UNION或者NUNION
- containsAll-> SUBSETP
- removeAll-> SET-DIFFERENCE或者NSET-DIFFERENCE
- keepAll->相交或者不相交
看cl容器。有一个集合容器类。
是的,它有套。请参阅《实践通用Lisp》中有关"集合"的这一部分。
基本上,我们可以创建带有pushnew和adjoin的集合,并使用member,member-if和member-if-not进行查询,并将其与具有诸如intersection之类的其他集合的组合,union,set-difference,set-exclusive-or和subsetp`。
使用哈希表可轻松解决。
(let ((h (make-hash-table :test 'equalp))) ; if you're storing symbols
(loop for i from 0 upto 20
do (setf (gethash i h) (format nil "Value ~A" i)))
(loop for i from 10 upto 30
do (setf (gethash i h) (format nil "~A eulaV" i)))
(loop for k being the hash-keys of h using (hash-value v)
do (format t "~A => ~A~%" k v)))
输出
0 => Value 0 1 => Value 1 ... 9 => Value 9 10 => 10 eulaV 11 => 11 eulaV ... 29 => 29 eulaV 30 => 30 eulaV
就个人而言,我只是实现一个接受列表并返回唯一集的函数。我一起草拟了一些对我有用的东西:
(defun make-set (list-in &optional (list-out '()))
(if (endp list-in)
(nreverse list-out)
(make-set
(cdr list-in)
(adjoin (car list-in) list-out :test 'equal))))
基本上,"添加"功能在且仅当列表中不存在该项目时才将其无损地添加到列表中,并接受可选的测试功能(Common Lisp"等于"功能之一)。我们也可以使用pushnew进行破坏性的操作,但是我发现尾递归实现要优雅得多。因此,Lisp确实导出了一些基本功能,使我们可以将列表作为一组使用。不需要内置的数据类型,因为我们可以使用不同的函数将内容放在列表的前面。
我所有这些数据的来源(不是函数,而是信息)都是Common Lisp HyperSpec和Common Lisp the Language(第二版)的组合。

