... |
... |
@@ -750,6 +750,18 @@ |
750
|
750
|
15)
|
751
|
751
|
|
752
|
752
|
(declaim (start-block list-to-hashtable union intersection set-difference))
|
|
753
|
+
|
|
754
|
+;; Main code to process a set function. INIT-RES initializes the
|
|
755
|
+;; value of RES, which holds the result of the set function.
|
|
756
|
+;; TEST-FORM is a form that tests whether to add the item from LIST1
|
|
757
|
+;; to RES.
|
|
758
|
+(defmacro process-set (init-res test-form)
|
|
759
|
+ `(let ((res ,init-res))
|
|
760
|
+ (dolist (item list1)
|
|
761
|
+ (when ,test-form
|
|
762
|
+ (push item res)))
|
|
763
|
+ res))
|
|
764
|
+
|
753
|
765
|
;; Convert a list to a hashtable. The hashtable does not handle
|
754
|
766
|
;; duplicated values in the list. Returns the hashtable.
|
755
|
767
|
(defun list-to-hashtable (list key test test-not)
|
... |
... |
@@ -791,18 +803,10 @@ |
791
|
803
|
(declare (inline member))
|
792
|
804
|
(when (and testp notp)
|
793
|
805
|
(error (intl:gettext "Test and test-not both supplied.")))
|
794
|
|
- (let ((res list2)
|
795
|
|
- (hashtable (list-to-hashtable list2 key test test-not)))
|
796
|
|
- (macrolet
|
797
|
|
- ((process (test-form)
|
798
|
|
- `(dolist (item list1)
|
799
|
|
- (unless ,test-form
|
800
|
|
- (push item res)))))
|
801
|
|
- (cond (hashtable
|
802
|
|
- (process (nth-value 1 (gethash (apply-key key item) hashtable))))
|
803
|
|
- (t
|
804
|
|
- (process (with-set-keys (member (apply-key key item) list2)))))
|
805
|
|
- res)))
|
|
806
|
+ (let ((hashtable (list-to-hashtable list2 key test test-not)))
|
|
807
|
+ (if hashtable
|
|
808
|
+ (process-set list2 (not (nth-value 1 (gethash (apply-key key item) hashtable))))
|
|
809
|
+ (process-set list2 (not (with-set-keys (member (apply-key key item) list2)))))))
|
806
|
810
|
|
807
|
811
|
|
808
|
812
|
(defun intersection (list1 list2 &key key
|
... |
... |
@@ -812,18 +816,10 @@ |
812
|
816
|
(if (and testp notp)
|
813
|
817
|
(error "Test and test-not both supplied."))
|
814
|
818
|
(let ((hashtable
|
815
|
|
- (list-to-hashtable list2 key test test-not)))
|
816
|
|
- (macrolet
|
817
|
|
- ((process (test-form)
|
818
|
|
- `(let ((res nil))
|
819
|
|
- (dolist (item list1)
|
820
|
|
- (if ,test-form
|
821
|
|
- (push item res)))
|
822
|
|
- res)))
|
823
|
|
- (cond (hashtable
|
824
|
|
- (process (nth-value 1 (gethash (apply-key key item) hashtable))))
|
825
|
|
- (t
|
826
|
|
- (process (with-set-keys (member (apply-key key item) list2))))))))
|
|
819
|
+ (list-to-hashtable list2 key test test-not)))
|
|
820
|
+ (if hashtable
|
|
821
|
+ (process-set nil (nth-value 1 (gethash (apply-key key item) hashtable)))
|
|
822
|
+ (process-set nil (with-set-keys (member (apply-key key item) list2))))))
|
827
|
823
|
|
828
|
824
|
(defun set-difference (list1 list2 &key key (test #'eql testp) (test-not nil notp))
|
829
|
825
|
"Returns the elements of list1 which are not in list2."
|
... |
... |
@@ -835,21 +831,10 @@ |
835
|
831
|
(return-from set-difference list1))
|
836
|
832
|
|
837
|
833
|
(let ((hashtable
|
838
|
|
- (list-to-hashtable list2 key test test-not)))
|
839
|
|
- (macrolet
|
840
|
|
- ((process (test-form)
|
841
|
|
- `(let ((res nil))
|
842
|
|
- (dolist (item list1)
|
843
|
|
- (if (not ,test-form)
|
844
|
|
- (push item res)))
|
845
|
|
- res)))
|
846
|
|
-
|
847
|
|
- (cond (hashtable
|
848
|
|
- (process (nth-value 1 (gethash (apply-key key item) hashtable))))
|
849
|
|
- (t
|
850
|
|
- ;; Default implementation because we didn't create the hash
|
851
|
|
- ;; table.
|
852
|
|
- (process (with-set-keys (member (apply-key key item) list2))))))))
|
|
834
|
+ (list-to-hashtable list2 key test test-not)))
|
|
835
|
+ (if hashtable
|
|
836
|
+ (process-set nil (not (nth-value 1 (gethash (apply-key key item) hashtable))))
|
|
837
|
+ (process-set nil (not (with-set-keys (member (apply-key key item) list2)))))))
|
853
|
838
|
|
854
|
839
|
|
855
|
840
|
(declaim (end-block))
|