Common Lisp有类似java的Set Interface /实现类吗?

时间:2008-10-03 05:17:01

标签: java lisp set sbcl

我需要类似this的东西,这是一个元素集合,不包含任何元素的重复。 Common Lisp,特别是SBCL,有这样的东西吗?

8 个答案:

答案 0 :(得分:6)

对于快速解决方案,只需使用哈希表,如前所述。

但是,如果您更喜欢更有原则的方法,可以查看FSet,它是“功能集理论集合库”。其中,它包含集合和包的类和操作。

(编辑:)最干净的方法可能是将面向集合的操作定义为通用函数。毕竟,一组通用函数基本上等同于Java接口。您可以简单地在标准HASH-TABLE类上实现方法作为第一个原型,并允许其他实现。

答案 1 :(得分:6)

看看cl-containers。有一个集合容器类。

答案 2 :(得分:5)

您可以使用列表,但它们可能被证明对于表示大型集合效率低下。这是使用ADJOIN或PUSHNEW将新元素添加到列表中,而DELETE or 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操作的对应物是:

答案 3 :(得分:5)

是的,它有套装。请参阅 Practical Common Lisp 中的this section on "Sets"

基本上,您可以使用pushnewadjoin创建一个集合,使用membermember-ifmember-if-not进行查询,并将其与其他集合结合使用使用intersectionunionset-differenceset-exclusive-orsubsetp等功能。

答案 4 :(得分:2)

使用哈希表轻松解决。

(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

答案 5 :(得分:1)

不是我知道的,但你可以使用hash tables来表达相似的东西。

答案 6 :(得分:0)

Lisp哈希表是基于CLOS的。规格here

答案 7 :(得分:0)

就个人而言,我只会实现一个获取列表并返回唯一集合的函数。我已经起草了一些适合我的东西:

(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))))

基本上,adjoin函数会非破坏性地将项目预先添加到列表中,当且仅当项目不在列表中时,接受可选的测试函数(Common Lisp“等于”函数之一) )。您也可以使用pushnew破坏性地执行此操作,但我发现尾递归实现更加优雅。因此,Lisp确实导出了几个基本函数,允许您将列表用作集合;不需要内置数据类型,因为您可以使用不同的函数将事物添加到列表中。

我所有这些的数据来源(不是功能,而是信息)是Common Lisp HyperSpecCommon Lisp the Language (2nd Edition)的组合。

相关问题