Mercurial > hg > xemacs-beta
diff lisp/hyperbole/set.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/hyperbole/set.el Mon Aug 13 08:45:50 2007 +0200 @@ -0,0 +1,220 @@ +;;!emacs +;; +;; FILE: set.el +;; SUMMARY: Provide general mathematical operators on unordered sets. +;; USAGE: GNU Emacs Lisp Library +;; KEYWORDS: extensions, tools +;; +;; AUTHOR: Bob Weiner +;; ORG: Brown U. +;; +;; ORIG-DATE: 26-Sep-91 at 19:24:19 +;; LAST-MOD: 14-Apr-95 at 16:17:03 by Bob Weiner +;; +;; This file is part of Hyperbole. +;; Available for use and distribution under the same terms as GNU Emacs. +;; +;; Copyright (C) 1991-1995, Free Software Foundation, Inc. +;; Developed with support from Motorola Inc. +;; +;; DESCRIPTION: +;; +;; All set operations herein work with sets of arbitrary Lisp objects, +;; including strings. By default, they use 'equal' for comparisons +;; but this may be overidden by changing the function bound to +;; the 'set:equal-op' variable. +;; +;; DESCRIP-END. + +;; ************************************************************************ +;; Other required Elisp libraries +;; ************************************************************************ + +;; ************************************************************************ +;; Public variables +;; ************************************************************************ + +(defvar set:equal-op 'equal + "Comparison function used by set operators. +It must be a function of two arguments which returns non-nil only when +the arguments are equivalent.") + +;; ************************************************************************ +;; Public functions +;; ************************************************************************ + +(defmacro set:add (elt set) + "Adds element ELT to SET and then returns SET. +Uses 'set:equal-op' for comparison. +Use (setq set (set:add elt set)) to assure set is always properly modified." + (` (cond ((set:member (, elt) (, set)) (, set)) + ((, set) (setq (, set) (cons (, elt) (, set)))) + (t (list (, elt)))))) + +(defun set:combinations (set &optional arity) + "Returns all possible combinations (subsets) of SET. +Assumes SET is a valid set. With optional ARITY, returns only subsets with +ARITY members." + (cond ((null arity) + (setq arity 0) + (cons nil (apply 'nconc (mapcar (function + (lambda (elt) + (setq arity (1+ arity)) + (set:combinations set arity))) + set)))) + ((= arity 1) set) + ((<= arity 0) '(nil)) + (t (let ((rest) (ctr 1)) + (apply + 'nconc + (mapcar (function + (lambda (first) + (setq rest (nthcdr ctr set) + ctr (1+ ctr)) + (mapcar (function + (lambda (elt) + (if (listp elt) (cons first elt) + (list first elt)))) + (set:combinations rest (1- arity))))) + set)))))) + +(defun set:create (&rest elements) + "Returns a new set created from any number of ELEMENTS or a list of ELEMENTS. +Uses 'set:equal-op' for comparison." + (let ((set)) + (mapcar (function + (lambda (elt) (or (set:member elt set) + (setq set (cons elt set))))) + (if (or (null (car elements)) (not (listp (car elements)))) + elements + (car elements))) + set)) + +(fset 'set:delete 'set:remove) +(defun set:difference (&rest sets) + "Returns difference of any number of SETS. +Difference is the set of elements in the first set that are not in any of the +other sets. Uses 'set:equal-op' for comparison." + (let ((rtn-set (set:members (car sets)))) + (mapcar + (function + (lambda (set) + (mapcar (function + (lambda (elt) (set:remove elt rtn-set))) + set))) + (cdr sets)) + rtn-set)) + +(defun set:equal (set1 set2) + "Returns t iff SET1 contains the same members as SET2. Both must be sets. +Uses 'set:equal-op' for comparison." + (and (listp set1) (listp set2) + (= (set:size set1) (set:size set2)) + (set:subset set1 set2))) + +(defun set:get (key set) + "Returns the value associated with KEY in SET or nil. +Elements of SET should be of the form (key . value)." + (cdr (car (let ((set:equal-op + (function (lambda (key elt) + (equal key (car elt)))))) + (set:member key set))))) + +(defun set:intersection (&rest sets) + "Returns intersection of all SETS given as arguments. +Uses 'set:equal-op' for comparison." + (let ((rtn-set)) + (mapcar + (function + (lambda (elt) + (or (memq nil (mapcar (function + (lambda (set) (set:member elt set))) + (cdr sets))) + (setq rtn-set (cons elt rtn-set))))) + (car sets)) + rtn-set)) + +(defun set:is (obj) + "Returns t if OBJ is a set (a list with no repeated elements). +Uses 'set:equal-op' for comparison." + (and (listp obj) + (let ((lst obj)) + (while (and (not (set:member (car lst) (cdr lst))) + (setq lst (cdr lst)))) + (null lst)))) + +(fset 'set:map 'mapcar) + +(defun set:member (elt set) + "Returns non-nil if ELT is an element of SET. +The value is actually the tail of SET whose car is ELT. +Uses 'set:equal-op' for comparison." + (while (and set (not (funcall set:equal-op elt (car set)))) + (setq set (cdr set))) + set) + +(defun set:members (list) + "Returns set of unique elements of LIST. +Uses 'set:equal-op' for comparison. See also 'set:create'." + (let ((set)) + (mapcar (function + (lambda (elt) (or (set:member elt set) (setq set (cons elt set))))) + list) + set)) + +(defmacro set:remove (elt set) + "Removes element ELT from SET and returns new set. +Assumes SET is a valid set. Uses 'set:equal-op' for comparison. +Use (setq set (set:remove elt set)) to assure set is always properly modified." + (` (let ((rest (set:member (, elt) (, set))) + (rtn (, set))) + (if rest + (cond ((= (length rtn) 1) (setq rtn nil)) + ((= (length rest) 1) + (setcdr (nthcdr (- (length rtn) 2) rtn) nil)) + (t (setcar rest (car (cdr rest))) + (setcdr rest (cdr (cdr rest)))))) + rtn))) + +(defun set:replace (key value set) + "Replaces or adds element whose car matches KEY with element (KEY . VALUE) in SET. +Returns set if modified, else nil. +Use (setq set (set:replace elt set)) to assure set is always properly modified. + +Uses 'set:equal-op' to match against KEY. Assumes each element in the set +has a car and a cdr." + (let ((elt-set (set:member key set))) + (if elt-set + ;; replace element + (progn (setcar elt-set (cons key value)) + set) + ;; add new element + (cons (cons key value) set)))) + +(fset 'set:size 'length) + +(defun set:subset (sub set) + "Returns t iff set SUB is a subset of SET. +Uses 'set:equal-op' for comparison." + (let ((is t)) + (mapcar (function (lambda (elt) (if is (setq is (set:member elt set))))) sub) + (and is t))) + +(defun set:union (&rest sets) + "Returns union of all SETS given as arguments. +Uses 'set:equal-op' for comparison." + (let ((rtn-set)) + (mapcar + (function + (lambda (set) (mapcar (function + (lambda (elt) + (setq rtn-set (set:add elt rtn-set)))) + set))) + sets) + rtn-set)) + +;; ************************************************************************ +;; Private variables +;; ************************************************************************ + +(provide 'set)