回答:
私は最も簡単な方法はハッシュテーブルを使うことだと思います:
(defun get-duplicates (list &optional test)
(let ((ht (make-hash-table :test (or test #'equal)))
ret)
(dolist (x list)
(incf (gethash x ht 0)))
(maphash (lambda (key value)
(when (> value 1)
(push key ret)))
ht)
ret))
(get-duplicates '(a 2 a b 3 2))
==> (2 a)
ダッシュを使用:
(defun find-duplicates (list)
"Return a list that contains each element from LIST that occurs more than once."
(--> list
(-group-by #'identity it)
(-filter (lambda (ele) (> (length ele) 2)) it)
(mapcar #'car it)))
簡単なテストスイート:
(ert-deftest nothing ()
(should-not (find-duplicates '())))
(ert-deftest no-duplicates ()
(should-not (find-duplicates '(1 2 3 4 5 6 7 "eight"))))
(ert-deftest single-duplicate ()
(should (equal (find-duplicates '(1 2 3 4 1))
'(1))))
(ert-deftest multiple-duplicates ()
(should (equal (sort (find-duplicates '(1 2 3 4 1 6 7 8 9 2))
#'<)
'(1 2))))
(ert-deftest string-duplicates ()
(should (equal (find-duplicates '(1 2 "three" 4 "three"))
'("three"))))
現在、各重複の最初の発生順にアイテムを返すようです-group-by
が、それを保証するものは何も見当たらないので、信頼できるとは思いません。ハッシュテーブルを使用すると、より効率的になる可能性がありますが、これは機能します。
これは@caseneuveの定義に似ています。
(defun report-dups (xs)
(delete-dups (cl-remove-if-not (lambda (x) (member x (cdr (member x xs)))) xs)))
しかし、すでにテスト済みの場合でも、リスト内の各要素をテストする必要があります。そして、彼らは走りdelete-dups
ます。
この定義は単純明快であり、非効率性に悩まされることはありません。
(defun report-dups (xs)
(let ((ys ()))
(while xs
(unless (member (car xs) ys) ; Don't check it if already known to be a dup.
(when (member (car xs) (cdr xs)) (push (car xs) ys)))
(setq xs (cdr xs)))
ys))
また、ハッシュテーブルソリューションよりも約6倍高速であるget-duplicates
ようです(上記)。