Есть ли в Common Lisp что-то вроде интерфейса набора / реализации классов Java?

Мне нужно что-то вроде это, коллекция элементов, не содержащая дубликатов каких-либо элементов. Есть ли в Common Lisp, особенно в SBCL, что-нибудь подобное?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
9
0
3 656
8

Ответы 8

Не то, чтобы я знал об этом, но вы можете использовать хеш-таблицы для чего-то очень похожего.

Хэш-таблицы Lisp основаны на CLOS. Технические характеристики здесь.

Умм ... стандартные хеш-таблицы CL являются экземпляры класса CLOS HASH-TABLE, для которых вы можете без проблем определять методы. Кроме того, в статье, на которую вы ссылаетесь, говорится о разновидности объектной системы, которая совсем не похожа на CLOS. В CLOS методы принадлежат универсальным функциям, а не объектам.

Matthias Benkard 03.10.2008 14:17

Хэш-таблицы Common Lisp упакованы в CLOS. Я не знаю, в каком смысле они «на основе CLOS». Например, у CLTL1 были хэш-таблицы, но не было CLOS.

Ken 21.02.2009 03:28

Для быстрого решения просто используйте хеш-таблицы, как уже упоминалось ранее.

Однако, если вы предпочитаете более принципиальный подход, вы можете взглянуть на 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 являются:

Это рекомендуемый подход для начала, а затем его оптимизация, если профилирование предполагает, что это необходимо.

wentbackward 02.02.2010 19:26

Посмотрите на 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-е издание).

Другие вопросы по теме