



Не то, чтобы я знал об этом, но вы можете использовать хеш-таблицы для чего-то очень похожего.
Хэш-таблицы Lisp основаны на CLOS. Технические характеристики здесь.
Хэш-таблицы Common Lisp упакованы в CLOS. Я не знаю, в каком смысле они «на основе CLOS». Например, у CLTL1 были хэш-таблицы, но не было CLOS.
Для быстрого решения просто используйте хеш-таблицы, как уже упоминалось ранее.
Однако, если вы предпочитаете более принципиальный подход, вы можете взглянуть на FSet, который является «функциональной теоретико-множественной библиотекой коллекций». Среди прочего, он содержит классы и операции для наборов и сумок.
(РЕДАКТИРОВАТЬ :) Самым чистым способом, вероятно, было бы определить ваши операции, ориентированные на набор, как общие функции. В конце концов, набор общих функций в основном эквивалентен интерфейсу Java. Вы можете просто реализовать методы в стандартном классе HASH-TABLE в качестве первого прототипа, а также разрешить другие реализации.
Вы можете использовать списки, хотя они могут оказаться неэффективными для представления больших наборов. Это делается с помощью ADJOIN или НАШИТЬ, чтобы добавить новый элемент в список, и УДАЛИТЬ или УДАЛИТЬ, чтобы сделать наоборот.
(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). Это нормально для наборов, содержащих числа или символы, но для наборов других объектов более глубокий тест на равенство, такой как РАВНЫЙ, должен быть указан как параметр ключевого слова: 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 являются:
Это рекомендуемый подход для начала, а затем его оптимизация, если профилирование предполагает, что это необходимо.
Посмотрите на cl-контейнеры. Есть класс-набор-контейнер.
Да, есть наборы. См. этот раздел "Наборы" из Практический Common 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))))
По сути, функция adjoin добавляет элемент к списку неразрушающим образом тогда и только тогда, когда этот элемент еще не присутствует в списке, принимая необязательную тестовую функцию (одну из функций «равенства» Common Lisp). Вы также можете использовать pushnew, чтобы сделать это деструктивно, но я считаю хвостовую рекурсивную реализацию гораздо более элегантной. Итак, Lisp действительно экспортирует несколько основных функций, которые позволяют вам использовать список как набор; встроенный тип данных не требуется, потому что вы можете просто использовать разные функции для добавления вещей в список.
Моим источником данных для всего этого (не функции, а информации) была комбинация Common Lisp HyperSpec и Common Lisp the Language (2-е издание).
Умм ... стандартные хеш-таблицы CL являются экземпляры класса CLOS HASH-TABLE, для которых вы можете без проблем определять методы. Кроме того, в статье, на которую вы ссылаетесь, говорится о разновидности объектной системы, которая совсем не похожа на CLOS. В CLOS методы принадлежат универсальным функциям, а не объектам.