作为CL的新手,我经常使用简单的算法。例如,我试图实现一个函数,用于删除列表中的所有唯一元素。
(1 2 2 3 3 4 5 3) -> (2 2 3 3 3)
第一次尝试导致以下代码:
(defun remove-unique (items)
(let ((duplicates (set-difference items (remove-duplicates items :test #'equal))))
(append duplicates (remove-duplicates duplicates :test #'equal))))这在字符串中工作正常,但总是返回数字的NIL。阅读更多关于set-difference的内容,我了解到它根本不适合使用重复填充的列表,在我的例子中它只是起作用,所以我放弃了不可移植的方法,继续前进。
另一种尝试是:
(defun remove-unique (items)
(loop for item in items
when (member item (cdr (member item items)))
collect item))这对于数字来说是可行的,但是返回字符串的NIL。
显然,在字符串和数字之间有一个核心的区别,我不明白。为什么列表处理函数(如member和set-difference )对它们的工作方式不同?
发布于 2013-08-13 22:10:15
字符串与列表比数字更相关,因为列表和字符串都是序列。
"Hello"是一个序列(复合数据类型),从原始字符值#\H开始,以#\o结尾。
'(1 2 3)是以基元数值1开头,以3结尾的序列(复合数据类型)。
字符与数字相似,因为它们是原始值。原语值可以使用eql进行比较,而不属于同一对象的序列可以使用equal进行比较。
(setq list1 (list 1 2 3))
(setq list2 (list 1 2 3))
(eql list1 list2)
;==> NIL
(equal list1 list2)
;==> T
;; comparing first element of both lists using eql
(eql (car list1) (car list2))
;==> T
(setq string1 "Hello")
(setq string2 "Hello")
(eql string1 string2)
;==> NIL
(equal string1 string2)
;==> T
;; comparing first character of both strings using eql
(eql (elt string1 0) (elt string2 0))
;==> T公共Lisp中的大多数函数(如果不是全部的话)通常都有一个可选的名为:test的参数,您可以在这里提供元素比较的方式。默认情况下通常是eql。为了使它们与序列相一致,您需要将#'equal作为:test提供。
发布于 2013-08-14 06:49:15
数字、字符和字符串的相等比较确实不同。Equal,您应该小心使用它,因为它更昂贵,结构相等(因此它下降到某些对象)。eq做对象相等。除了数字(检查类型和值)和字符(检查“值”)外,大多数情况下eql都是对象相等的。
有关更多信息,请参见相等、eql和情商的hyperspec条目。
发布于 2013-08-13 09:52:41
(defun remove-unique (items &key (test 'eql))
(loop
:with table := (make-hash-table :test test)
:for element :in items :do
(setf (gethash element table)
(1+ (gethash element table 0)))
:finally
(return
(loop
:for k :being :the :hash-keys :of table
:using (:hash-value v)
:when (> v 1) :nconc (make-list v :initial-element k)))))
(defun remove-unique (items &key (test 'eql))
(loop
:with table := (make-hash-table :test test)
:for element :in items :do
(setf (gethash element table)
(1+ (gethash element table 0)))
:finally
(return
(loop
:for element :in items
:unless (= 1 (gethash element table))
:collect element))))我可能会使用第一个变体,因为它减少了对哈希表的读取,但是您需要检查列表中的项以后没有修改。
(remove-unique '("1" "2" "2" "3" "3" "4" "5" "3") :test #'equal)给予:
("2" "2" "3" "3" "3")但
(remove-unique '("1" "2" "2" "3" "3" "4" "5" "3"))给予:
NILhttps://stackoverflow.com/questions/18205073
复制相似问题