[Git][cmucl/cmucl][issue-240-set-diff-with-hash-table] Refactoring of list to hashtable to its own function
Raymond Toy (@rtoy)
gitlab at common-lisp.net
Wed Jun 14 16:10:45 UTC 2023
Raymond Toy pushed to branch issue-240-set-diff-with-hash-table at cmucl / cmucl
Commits:
5e47bcfc by Raymond Toy at 2023-06-14T09:08:48-07:00
Refactoring of list to hashtable to its own function
Move the code for converting a list to a hash table to its own
function. Also support using a key function.
Update set-difference to use this new function.
- - - - -
1 changed file:
- src/code/list.lisp
Changes:
=====================================
src/code/list.lisp
=====================================
@@ -745,6 +745,41 @@
(cons item list)))
+;; Convert a list to a hashtable. Given 2 lists, find the shorter of
+;; the two lists and add the shorter list to a hashtable.
+(defun list-to-hashtable (list1 list2 &key test test-not key)
+ ;; Don't currently support test-not when converting a list to a hashtable
+ (unless test-not
+ (let ((hash-test (let ((test-fn (if (and (symbolp test)
+ (fboundp test))
+ (fdefinition test)
+ test)))
+ (cond ((eql test-fn #'eq) 'eq)
+ ((eql test-fn #'eql) 'eql)
+ ((eql test-fn #'equal) 'equal)
+ ((eql test-fn #'equalp) 'equalp)))))
+ (unless hash-test
+ (return-from list-to-hashtable (values nil nil)))
+ (multiple-value-bind (len shorter-list)
+ (do ((length 0 (1+ length))
+ (l1 list1 (cdr l1))
+ (l2 list2 (cdr l2)))
+ ((cond ((null l1)
+ (return (values length list1)))
+ ((null l2)
+ (return (values length list2))))))
+ (when (< len 15)
+ (return-from list-to-hashtable (values nil nil)))
+ (flet ((build-hash (len list)
+ (let ((hashtable (make-hash-table :test test :size len)))
+ (dolist (item list)
+ (setf (gethash (apply-key key item) hashtable) item))
+ hashtable)))
+ (cond ((eq shorter-list list2)
+ (values (build-hash len list2) list2))
+ ((eq shorter-list list1)
+ (values (build-hash len list1) list1))))))))
+
;;; UNION -- Public.
;;;
;;; This function assumes list2 is the result, adding to it from list1 as
@@ -812,53 +847,37 @@
(setq list1 (Cdr list1))))
res))
-(defun set-difference (list1 list2 &key key
- (test #'eql testp) (test-not nil notp))
+(defun set-difference (list1 list2 &key key (test #'eql testp) (test-not nil notp))
"Returns the elements of list1 which are not in list2."
(declare (inline member))
(if (and testp notp)
(error "Test and test-not both supplied."))
- (flet ((default-impl (list1 list2)
- (if (null list2)
+ (multiple-value-bind (hashtable shorter-list)
+ (list-to-hashtable list1 list2 :key key :test test :test-not test-not)
+ (cond ((null hashtable)
+ ;; Default implementation because we didn't create the hash
+ ;; table.
+ (if (null list2)
list1
(let ((res nil))
(dolist (elt list1)
(if (not (with-set-keys (member (apply-key key elt) list2)))
(push elt res)))
- res))))
- (cond ((and testp (null key)
- (member test (list #'eq #'eql #'equal #'equalp)))
- (multiple-value-bind (len shorter-list)
- (do ((length 0 (1+ length))
- (l1 list1 (cdr l1))
- (l2 list2 (cdr l2)))
- ((cond ((null l1)
- (return (values length list1)))
- ((null l2)
- (return (values length list2))))))
- (when (< len 20)
- (return-from set-difference (default-impl list1 list2)))
- (flet ((build-hash (len list)
- (let ((hashtable (make-hash-table :test test :size len)))
- (dolist (item list)
- (setf (gethash item hashtable) t))
- hashtable)))
- (cond ((eq shorter-list list2)
- (let ((hashtable (build-hash len list2))
- diff)
- (dolist (item list1)
- (unless (gethash item hashtable)
- (push item diff)))
- diff))
- ((eq shorter-list list1)
- (let ((hashtable (build-hash len list1)))
- (dolist (item list2)
- (when (gethash item hashtable)
- (remhash item hashtable)))
- (loop for item being the hash-keys of hashtable
- collect item)))))))
- (t
- (default-impl list1 list2)))))
+ res)))
+ ((eq shorter-list list2)
+ ;; list2 was placed in hash table.
+ (let (diff)
+ (dolist (item list1)
+ (unless (gethash (apply-key key item) hashtable)
+ (push item diff)))
+ diff))
+ ((eq shorter-list list1)
+ ;; list1 was placed in the hash table.
+ (dolist (item list2)
+ (when (gethash (apply-key key item) hashtable)
+ (remhash item hashtable)))
+ (loop for item being the hash-values of hashtable
+ collect item)))))
(defun nset-difference (list1 list2 &key key
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/commit/5e47bcfc5129d5d7b47b11060adf21a716930838
--
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/commit/5e47bcfc5129d5d7b47b11060adf21a716930838
You're receiving this email because of your account on gitlab.common-lisp.net.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/cmucl-cvs/attachments/20230614/24841f72/attachment-0001.html>
More information about the cmucl-cvs
mailing list