... |
... |
@@ -749,6 +749,7 @@ |
749
|
749
|
(defparameter *min-list-length-for-hashtable*
|
750
|
750
|
15)
|
751
|
751
|
|
|
752
|
+(declaim (start-block list-to-hashtable union intersection set-difference))
|
752
|
753
|
;; Convert a list to a hashtable. The hashtable does not handle
|
753
|
754
|
;; duplicated values in the list. Returns the hashtable.
|
754
|
755
|
(defun list-to-hashtable (list key test test-not)
|
... |
... |
@@ -802,6 +803,57 @@ |
802
|
803
|
(push item res)))))
|
803
|
804
|
res))
|
804
|
805
|
|
|
806
|
+
|
|
807
|
+(defun intersection (list1 list2 &key key
|
|
808
|
+ (test #'eql testp) (test-not nil notp))
|
|
809
|
+ "Returns the intersection of list1 and list2."
|
|
810
|
+ (declare (inline member))
|
|
811
|
+ (if (and testp notp)
|
|
812
|
+ (error "Test and test-not both supplied."))
|
|
813
|
+ (let ((hashtable
|
|
814
|
+ (list-to-hashtable list2 key test test-not)))
|
|
815
|
+ (cond (hashtable
|
|
816
|
+ (let ((res nil))
|
|
817
|
+ (dolist (item list1)
|
|
818
|
+ (when (nth-value 1 (gethash (apply-key key item) hashtable))
|
|
819
|
+ (push item res)))
|
|
820
|
+ res))
|
|
821
|
+ ((null hashtable)
|
|
822
|
+ (let ((res nil))
|
|
823
|
+ (dolist (elt list1)
|
|
824
|
+ (if (with-set-keys (member (apply-key key elt) list2))
|
|
825
|
+ (push elt res)))
|
|
826
|
+ res)))))
|
|
827
|
+
|
|
828
|
+(defun set-difference (list1 list2 &key key (test #'eql testp) (test-not nil notp))
|
|
829
|
+ "Returns the elements of list1 which are not in list2."
|
|
830
|
+ (declare (inline member))
|
|
831
|
+ (if (and testp notp)
|
|
832
|
+ (error "Test and test-not both supplied."))
|
|
833
|
+ ;; Quick exit
|
|
834
|
+ (when (null list2)
|
|
835
|
+ (return-from set-difference list1))
|
|
836
|
+
|
|
837
|
+ (let ((hashtable
|
|
838
|
+ (list-to-hashtable list2 key test test-not)))
|
|
839
|
+ (cond (hashtable
|
|
840
|
+ ;; list2 was placed in hash table.
|
|
841
|
+ (let ((res nil))
|
|
842
|
+ (dolist (item list1)
|
|
843
|
+ (unless (nth-value 1 (gethash (apply-key key item) hashtable))
|
|
844
|
+ (push item res)))
|
|
845
|
+ res))
|
|
846
|
+ ((null hashtable)
|
|
847
|
+ ;; Default implementation because we didn't create the hash
|
|
848
|
+ ;; table.
|
|
849
|
+ (let ((res nil))
|
|
850
|
+ (dolist (item list1)
|
|
851
|
+ (if (not (with-set-keys (member (apply-key key item) list2)))
|
|
852
|
+ (push item res)))
|
|
853
|
+ res)))))
|
|
854
|
+
|
|
855
|
+(declaim (end-block))
|
|
856
|
+
|
805
|
857
|
;;; Destination and source are setf-able and many-evaluable. Sets the source
|
806
|
858
|
;;; to the cdr, and "conses" the 1st elt of source to destination.
|
807
|
859
|
;;;
|
... |
... |
@@ -834,28 +886,6 @@ |
834
|
886
|
(process (with-set-keys (member (apply-key key (car list1)) list2)))))
|
835
|
887
|
res)))
|
836
|
888
|
|
837
|
|
-
|
838
|
|
-(defun intersection (list1 list2 &key key
|
839
|
|
- (test #'eql testp) (test-not nil notp))
|
840
|
|
- "Returns the intersection of list1 and list2."
|
841
|
|
- (declare (inline member))
|
842
|
|
- (if (and testp notp)
|
843
|
|
- (error "Test and test-not both supplied."))
|
844
|
|
- (let ((hashtable
|
845
|
|
- (list-to-hashtable list2 key test test-not)))
|
846
|
|
- (cond (hashtable
|
847
|
|
- (let ((res nil))
|
848
|
|
- (dolist (item list1)
|
849
|
|
- (when (nth-value 1 (gethash (apply-key key item) hashtable))
|
850
|
|
- (push item res)))
|
851
|
|
- res))
|
852
|
|
- ((null hashtable)
|
853
|
|
- (let ((res nil))
|
854
|
|
- (dolist (elt list1)
|
855
|
|
- (if (with-set-keys (member (apply-key key elt) list2))
|
856
|
|
- (push elt res)))
|
857
|
|
- res)))))
|
858
|
|
-
|
859
|
889
|
(defun nintersection (list1 list2 &key key
|
860
|
890
|
(test #'eql testp) (test-not nil notp))
|
861
|
891
|
"Destructively returns the intersection of list1 and list2."
|
... |
... |
@@ -882,33 +912,6 @@ |
882
|
912
|
(setq list1 (Cdr list1))))
|
883
|
913
|
res)))
|
884
|
914
|
|
885
|
|
-(defun set-difference (list1 list2 &key key (test #'eql testp) (test-not nil notp))
|
886
|
|
- "Returns the elements of list1 which are not in list2."
|
887
|
|
- (declare (inline member))
|
888
|
|
- (if (and testp notp)
|
889
|
|
- (error "Test and test-not both supplied."))
|
890
|
|
- ;; Quick exit
|
891
|
|
- (when (null list2)
|
892
|
|
- (return-from set-difference list1))
|
893
|
|
-
|
894
|
|
- (let ((hashtable
|
895
|
|
- (list-to-hashtable list2 key test test-not)))
|
896
|
|
- (cond (hashtable
|
897
|
|
- ;; list2 was placed in hash table.
|
898
|
|
- (let ((res nil))
|
899
|
|
- (dolist (item list1)
|
900
|
|
- (unless (nth-value 1 (gethash (apply-key key item) hashtable))
|
901
|
|
- (push item res)))
|
902
|
|
- res))
|
903
|
|
- ((null hashtable)
|
904
|
|
- ;; Default implementation because we didn't create the hash
|
905
|
|
- ;; table.
|
906
|
|
- (let ((res nil))
|
907
|
|
- (dolist (item list1)
|
908
|
|
- (if (not (with-set-keys (member (apply-key key item) list2)))
|
909
|
|
- (push item res)))
|
910
|
|
- res)))))
|
911
|
|
-
|
912
|
915
|
(defun nset-difference (list1 list2 &key key
|
913
|
916
|
(test #'eql testp) (test-not nil notp))
|
914
|
917
|
"Destructively returns the elements of list1 which are not in list2."
|
... |
... |
@@ -935,7 +938,6 @@ |
935
|
938
|
(setq list1 (cdr list1))))
|
936
|
939
|
res)))
|
937
|
940
|
|
938
|
|
-
|
939
|
941
|
(defun set-exclusive-or (list1 list2 &key key
|
940
|
942
|
(test #'eql testp) (test-not nil notp))
|
941
|
943
|
"Return new list of elements appearing exactly once in LIST1 and LIST2."
|