comparison lisp/cl-seq.el @ 5067:7d7ae8db0341

add functions `stable-union' and `stable-intersection' to do stable set operations -------------------- ChangeLog entries follow: -------------------- lisp/ChangeLog addition: 2010-02-22 Ben Wing <ben@xemacs.org> * cl-seq.el: * cl-seq.el (stable-union): New. * cl-seq.el (stable-intersection): New. New functions to do stable set operations, i.e. preserve the order of the elements in the argument lists, and prefer LIST1 over LIST2 when ordering the combined result. The result looks as much like LIST1 as possible, followed (in the case of `stable-union') by any necessary elements from LIST2, in order. This is contrary to `union' and `intersection', which are not required to be order- preserving and are not -- they prefer LIST2 and output results in backwards order.
author Ben Wing <ben@xemacs.org>
date Mon, 22 Feb 2010 21:23:02 -0600
parents 545ec923b4eb
children 6afe991b8135
comparison
equal deleted inserted replaced
5066:545ec923b4eb 5067:7d7ae8db0341
848 Keywords supported: :test :test-not :key 848 Keywords supported: :test :test-not :key
849 See `union' for the meaning of :test, :test-not and :key." 849 See `union' for the meaning of :test, :test-not and :key."
850 (cond ((null cl-list1) cl-list2) ((null cl-list2) cl-list1) 850 (cond ((null cl-list1) cl-list2) ((null cl-list2) cl-list1)
851 (t (apply 'union cl-list1 cl-list2 cl-keys)))) 851 (t (apply 'union cl-list1 cl-list2 cl-keys))))
852 852
853 ;; XEmacs addition: NOT IN COMMON LISP.
854 (defun stable-union (cl-list1 cl-list2 &rest cl-keys)
855 "Stably combine LIST1 and LIST2 using a set-union operation.
856 The result list contains all items that appear in either LIST1 or LIST2.
857 The result is \"stable\" in that it preserves the ordering of elements in
858 LIST1 and LIST2. The result specifically consists of the elements in LIST1
859 in order, followed by any elements in LIST2 that are not also in LIST1, in
860 the order given in LIST2.
861 This is a non-destructive function; it makes a copy of the data if necessary
862 to avoid corrupting the original LIST1 and LIST2.
863 Keywords supported: :test :test-not :key
864 See `union' for the meaning of :test, :test-not and :key.
865
866 NOTE: This is *NOT* a function defined by Common Lisp, but an XEmacs
867 extension."
868 ;; The standard `union' doesn't produce a "stable" union --
869 ;; it iterates over the second list instead of the first one, and returns
870 ;; the values in backwards order. According to the CLTL2 documentation,
871 ;; `union' is not required to preserve the ordering of elements in
872 ;; any fashion, so we add a new function rather than changing the
873 ;; semantics of `union'.
874 (cond ((null cl-list1) cl-list2) ((null cl-list2) cl-list1)
875 ((equal cl-list1 cl-list2) cl-list1)
876 (t
877 (append
878 cl-list1
879 (cl-parsing-keywords (:key) (:test :test-not)
880 (loop for cl-l in cl-list2
881 if (not (if (or cl-keys (numberp cl-l))
882 (apply 'member* (cl-check-key cl-l)
883 cl-list1 cl-keys)
884 (memq cl-l cl-list1)))
885 collect cl-l))))))
886
853 (defun intersection (cl-list1 cl-list2 &rest cl-keys) 887 (defun intersection (cl-list1 cl-list2 &rest cl-keys)
854 "Combine LIST1 and LIST2 using a set-intersection operation. 888 "Combine LIST1 and LIST2 using a set-intersection operation.
855 The result list contains all items that appear in both LIST1 and LIST2. 889 The result list contains all items that appear in both LIST1 and LIST2.
856 This is a non-destructive function; it makes a copy of the data if necessary 890 This is a non-destructive function; it makes a copy of the data if necessary
857 to avoid corrupting the original LIST1 and LIST2. 891 to avoid corrupting the original LIST1 and LIST2.
879 whenever possible. 913 whenever possible.
880 Keywords supported: :test :test-not :key 914 Keywords supported: :test :test-not :key
881 See `union' for the meaning of :test, :test-not and :key." 915 See `union' for the meaning of :test, :test-not and :key."
882 (and cl-list1 cl-list2 (apply 'intersection cl-list1 cl-list2 cl-keys))) 916 (and cl-list1 cl-list2 (apply 'intersection cl-list1 cl-list2 cl-keys)))
883 917
918 ;; XEmacs addition: NOT IN COMMON LISP.
919 (defun stable-intersection (cl-list1 cl-list2 &rest cl-keys)
920 "Stably combine LIST1 and LIST2 using a set-intersection operation.
921 The result list contains all items that appear in both LIST1 and LIST2.
922 The result is \"stable\" in that it preserves the ordering of elements in
923 LIST1 that are also in LIST2.
924 This is a non-destructive function; it makes a copy of the data if necessary
925 to avoid corrupting the original LIST1 and LIST2.
926 Keywords supported: :test :test-not :key
927 See `union' for the meaning of :test, :test-not and :key.
928
929 NOTE: This is *NOT* a function defined by Common Lisp, but an XEmacs
930 extension."
931 ;; The standard `intersection' doesn't produce a "stable" intersection --
932 ;; it iterates over the second list instead of the first one, and returns
933 ;; the values in backwards order. According to the CLTL2 documentation,
934 ;; `intersection' is not required to preserve the ordering of elements in
935 ;; any fashion, so we add a new function rather than changing the
936 ;; semantics of `intersection'.
937 (and cl-list1 cl-list2
938 (if (equal cl-list1 cl-list2) cl-list1
939 (cl-parsing-keywords (:key) (:test :test-not)
940 (loop for cl-l in cl-list1
941 if (if (or cl-keys (numberp cl-l))
942 (apply 'member* (cl-check-key cl-l)
943 cl-list2 cl-keys)
944 (memq cl-l cl-list2))
945 collect cl-l)))))
946
884 (defun set-difference (cl-list1 cl-list2 &rest cl-keys) 947 (defun set-difference (cl-list1 cl-list2 &rest cl-keys)
885 "Combine LIST1 and LIST2 using a set-difference operation. 948 "Combine LIST1 and LIST2 using a set-difference operation.
886 The result list contains all items that appear in LIST1 but not LIST2. 949 The result list contains all items that appear in LIST1 but not LIST2.
887 This is a non-destructive function; it makes a copy of the data if necessary 950 This is a non-destructive function; it makes a copy of the data if necessary
888 to avoid corrupting the original LIST1 and LIST2. 951 to avoid corrupting the original LIST1 and LIST2.