9

このようなものが必要です。これは、要素の重複を含まない要素のコレクションです。Common Lisp、特に SBCL には、このようなものがありますか?

4

8 に答える 8

6

簡単な解決策としては、前述のようにハッシュ テーブルを使用するだけです。

ただし、より原則的なアプローチを好む場合は、「機能集合論的コレクション ライブラリ」であるFSetを参照してください。特に、セットとバッグのクラスと操作が含まれています。

(EDIT :) 最もクリーンな方法は、おそらくセット指向の操作をジェネリック関数として定義することです。結局、汎用関数のセットは基本的に Java インターフェースと同等です。最初のプロトタイプとして標準の HASH-TABLE クラスにメソッドを実装するだけで、他の実装も許可できます。

于 2008-10-03T07:51:11.897 に答える
6

cl-containersを見てください。セットコンテナクラスがあります。

于 2008-10-03T11:53:20.977 に答える
4

リストを使用することもできますが、大きなセットを表すには非効率的であることがわかります。これは、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}

注意すべきことの 1 つは、これらのオペレーターがデフォルトで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"}

Java の Set 操作の一部に対応する Lisp の操作は次のとおりです。

于 2008-10-03T10:38:19.717 に答える
4

はい、セットがあります。Practical Common Lisp「セット」に関するこのセクションを参照してください。

基本的に、 と でセットを作成し、pushnewadjoin、 でクエリを実行しmember、 、member-if、、などの関数をmember-if-not使用して他のセットと組み合わせることができます。intersectionunionset-differenceset-exclusive-orsubsetp

于 2008-10-03T13:29:56.477 に答える
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
于 2008-10-05T04:50:27.897 に答える
1

私が知っているわけではありませんが、非常に似たものにハッシュテーブルを使用できます。

于 2008-10-03T05:27:37.997 に答える
0

Lisp ハッシュテーブルは CLOS ベースです。スペックはこちら

于 2008-10-03T06:11:53.037 に答える
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 の "equal" 関数の 1 つ) を受け入れて、項目がリストにまだ存在しない場合にのみ、項目を非破壊的にリストの先頭に追加します。を使用して破壊的に行うこともできpushnewますが、末尾再帰の実装の方がはるかに洗練されていることがわかります。そのため、Lisp は、リストをセットとして使用できるようにするいくつかの基本的な関数をエクスポートします。リストの前にさまざまな関数を使用できるため、組み込みのデータ型は必要ありません。

これらすべて (関数ではなく情報) の私のデータ ソースは、Common Lisp HyperSpecCommon Lisp the Language (2nd Edition)の組み合わせです。

于 2008-10-26T23:27:35.117 に答える