代码之家  ›  专栏  ›  技术社区  ›  Paul Wicks asgeo1

普通LISP是否有类似Java的设置接口/实现类?

  •  9
  • Paul Wicks asgeo1  · 技术社区  · 16 年前

    我需要一些像 this ,元素的集合,其中不包含任何元素的重复项。普通的lisp,特别是sbcl,有这样的东西吗?

    8 回复  |  直到 16 年前
        1
  •  6
  •   Matthias Benkard    16 年前

    如前所述,为了快速解决问题,只需使用哈希表。

    但是,如果你更喜欢原则性的方法,你可以看看 FSet ,这是一个功能集合论集合库。除此之外,它还包含集合和行李的类和操作。

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

        2
  •  6
  •   Jacek Szymański    16 年前

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

        3
  •  5
  •   Tamelite    16 年前

    您可以使用列表,尽管它们在表示大型集合时可能被证明是低效的。使用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使用均等方法一样)。对于包含数字或字符的集合来说,这是可以的,但是对于其他对象的集合来说,一个“更深入”的相等测试,比如 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的一些操作的对应点是:

        4
  •  5
  •   Matt Curtis    16 年前

    是的,有套。见 this section on "Sets" 实用通用语言 .

    基本上,你可以用 pushnew adjoin ,查询 member , member-if member-if-not ,并将其与具有以下函数的其他集合组合 intersection , union , set-difference , set-exclusive-or subsetp .

        5
  •  2
  •   Mikael Jansson    16 年前

    使用哈希表很容易解决。

    (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
    
        6
  •  1
  •   C. K. Young    16 年前

    我不知道,但你可以用 hash tables 类似的事情。

        7
  •  0
  •   dsm    16 年前

    lisp哈希表是基于clos的。规格 here .

        8
  •  0
  •   zvoase    16 年前

    就我个人而言,我只需要实现一个函数,它接受一个列表并返回一个唯一的集合。我已经起草了一些对我有用的东西:

    (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 函数在且仅当列表中不存在项时,以非破坏性方式将项预处理到列表中,接受可选的测试函数(常用的lisp“equal”函数之一)。你也可以使用 pushnew 这样做具有破坏性,但我发现尾部递归实现要优雅得多。因此,lisp确实导出了几个基本函数,这些函数允许您将一个列表用作一个集合;不需要内置数据类型,因为您只需使用不同的函数来将内容前置到列表。

    我所有这些(不是函数,而是信息)的数据源是 Common Lisp HyperSpec Common Lisp the Language (2nd Edition) .