Does Common Lisp have a something like java's

2020-03-12 05:37发布

I need something like this, a collection of elements which contains no duplicates of any element. Does Common Lisp, specifically SBCL, have any thing like this?

标签: java lisp set sbcl
8条回答
再贱就再见
2楼-- · 2020-03-12 05:56

You could use lists, though they can prove to be inefficient for representing large sets. This is done using ADJOIN or PUSHNEW to add a new element to a list, and DELETE or REMOVE to do the opposite.

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

One thing to watch out for is all that these operators use EQL by default to test for potential duplicates in the set (much as Java uses the equals method). That's OK for sets holding numbers or characters, but for sets of other objects, a `deeper' equality test such as EQUAL should be specified as a :TEST keyword parameter, e.g. for a set of strings :-

(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's counterparts to some of Java's Set operations are:

查看更多
叼着烟拽天下
3楼-- · 2020-03-12 05:59

For a quick solution, just use hash tables, as has been mentioned before.

However, if you prefer a more principled approach, you can take a look at FSet, which is “a functional set-theoretic collections library”. Among others, it contains classes and operations for sets and bags.

(EDIT:) The cleanest way would probably be to define your set-oriented operations as generic functions. A set of generic functions is basically equivalent to a Java interface, after all. You can simply implement methods on the standard HASH-TABLE class as a first prototype and allow other implementations as well.

查看更多
该账号已被封号
4楼-- · 2020-03-12 06:02

Lisp hashtables are CLOS based. Specs here.

查看更多
Root(大扎)
5楼-- · 2020-03-12 06:06

Look at cl-containers. There is a set-container class.

查看更多
一夜七次
6楼-- · 2020-03-12 06:09

Personally, I would just implement a function which takes a list and return a unique set. I've drafted something together which works for me:

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

Basically, the adjoin function prepends an item to a list non-destructively if and only if the item is not already present in the list, accepting an optional test function (one of the Common Lisp "equal" functions). You can also use pushnew to do so destructively, but I find the tail-recursive implementation to be far more elegant. So, Lisp does export several basic functions that allow you to use a list as a set; no built-in datatype is needed because you can just use different functions for prepending things to a list.

My data source for all of this (not the function, but the info) has been a combination of the Common Lisp HyperSpec and Common Lisp the Language (2nd Edition).

查看更多
ゆ 、 Hurt°
7楼-- · 2020-03-12 06:10

Easily solvable using a hash table.

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

outputs

0 => Value 0
1 => Value 1
...
9 => Value 9
10 => 10 eulaV
11 => 11 eulaV
...
29 => 29 eulaV
30 => 30 eulaV
查看更多
登录 后发表回答