set.py

Go to the documentation of this file.
00001 ##
00002 # 
00003 # This module implements a class Set using lists.  Using lists
00004 # allows the Set class to be general, but it can be inefficient
00005 # for sets with large numbers of elements.  If you need speed,
00006 # consider using the setf.py implementation, which uses dictionaries
00007 # to store set elements.  It's fast, but the tradeoff is that
00008 # you can only store hashable objects, which appear to me to be
00009 # numbers and strings.
00010 # 
00011 # Both set.py and setf.py have the identical set of class methods
00012 # and attributes.
00013 # 
00014 # The class is named Set in both cases.  If you import the class with
00015 # a statement like 'import Set from set', you can change to the
00016 # other implementation by just changing it to 'import Set from setf'.
00017 # 
00018 # Copyright (C) 2002 GDS Software
00019 # 
00020 # This program is free software; you can redistribute it and/or
00021 # modify it under the terms of the GNU General Public License as
00022 # published by the Free Software Foundation; either version 2 of
00023 # the License, or (at your option) any later version.
00024 # 
00025 # This program is distributed in the hope that it will be useful,
00026 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00027 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00028 # GNU General Public License for more details.
00029 # 
00030 # You should have received a copy of the GNU General Public
00031 # License along with this program; if not, write to the Free
00032 # Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00033 # MA  02111-1307  USA
00034 # 
00035 # See http://www.gnu.org/licenses/licenses.html for more details.
00036 # 
00037 
00038 __version__ = "$Id: set.py,v 1.3 2002/08/21 12:41:49 donp Exp $"
00039 
00040 ##
00041 # Class that implements a set.  The supported methods are:
00042 #         
00043 #         add_to_set(element)
00044 #             Adds the element to the set.  Element can be a list, tuple,
00045 #             dictionary, string, number, or set.  If it is a list, tuple, 
00046 #             dictionary, or set and self.decompose is true, it is broken 
00047 #             into its component parts and those are stored in the set 
00048 #             (otherwise element is just added to the set).
00049 #         delete_from_set(element)
00050 #             Deletes the element from the set.  Element can be a list, 
00051 #             tuple, dictionary, string, number, or a set.  If it is a
00052 #             list, tuple, dictionary, or set and self.decompose is true,
00053 #             element is broken into its component parts and each part is
00054 #             deleted from the set.  An exception will occur if one of 
00055 #             the elements is not in the set and self.harsh is true.  
00056 #         intersection(other_set)
00057 #             Returns a set that is the intersection of self and other_set.
00058 #         union(other_set)
00059 #             Returns a set that is the union of self and other_set.
00060 #         difference(other_set)
00061 #             Returns a set that consists of all elements in self that are
00062 #             not in other_set.
00063 #         is_in_set(element)
00064 #             Returns 1 if element is in the set, 0 if not.
00065 #         is_empty_set()
00066 #             Returns 1 if the set is empty.
00067 #         is_subset_of(other_set)
00068 #             Returns 1 if self is a subset of other_set; otherwise returns 0.
00069 #         is_proper_subset_of(other_set)
00070 #             Returns 1 if self is a proper subset of other_set; otherwise 
00071 #             returns 0.
00072 #         list()
00073 #             Returns a list of the elements of the set.
00074 #         __len__()
00075 #             Returns the number of elements in the set.
00076 #         __getitem__(element)
00077 #             Returns 1 if element is in set, 0 if not.
00078 #         __and__(other_set)
00079 #         __mul__(other_set)
00080 #         __rmul__(other_set)
00081 #             Same as intersection method.
00082 #         __or__(other_set)
00083 #         __add__(other_set)
00084 #         __radd__(other_set)
00085 #             Same as union method.
00086 #         __repr__
00087 #             Returns a string representation of the set.
00088 #         __sub__
00089 #             Same as difference() method.
00090 #         __cmp__(other_set)
00091 #             Returns 0 if self and other_set have the same member elements,
00092 #             otherwise returns 1.
00093 #         __repr__()
00094 #             Returns a string representation of the Set object.
00095 # 
00096 #     Because of the supported methods, you may use sets in the following
00097 #     ways; assumes r, s, and t are set objects:
00098 #         
00099 #         t = r + s      Union
00100 #         t = r | s      Union
00101 #         t = r * s      Intersection
00102 #         t = r & s      Intersection
00103 #         t = r - s      Difference
00104 #         r == s         Equality
00105 #         r != s         Non-equality
00106 #         s["a"]         Returns 1 if the string "a" is in set.
00107 # 
00108 #     You can pass in a dictionary, list, or tuple and it will be
00109 #     converted to a set.  If you pass in a dictionary, the keys are
00110 #     the set elements (the values are ignored).
00111 # 
00112 #     Attributes & parameters:
00113 # 
00114 #         sorted         Set to true to sort the set before printing or
00115 #                        returning as a list.  Default is false.
00116 # 
00117 #         harsh          If true, causes an exception to be thrown if you 
00118 #                        try to delete an element not in the list.  Defaults
00119 #                        to true.
00120 # 
00121 #         decompose      (Parameter to constructor)  Set this to true
00122 #                        if you want the value parameter decomposed into
00123 #                        its components and those components then make
00124 #                        up the set.  If the decompose parameter is false, 
00125 #                        the value parameter becomes the one and only 
00126 #                        element of the set.  Default is true.
00127 # 
00128 #         version        The class version string (it's maintained with
00129 #                        RCS).
00130 # 
00131 #     
00132 class Set:
00133 
00134     def __init__(self, value=None, decompose=1, harsh=1, sorted=0):
00135         self.set       = []
00136         self.sorted    = sorted
00137         self.harsh     = harsh
00138         self.decompose = decompose
00139         self.version   = "$Id: set.py,v 1.3 2002/08/21 12:41:49 donp Exp $"
00140         if value != None:
00141             if (type(value) == type([]) or type(value) == type(()) or                 type(value) == type({}) or type(value) == type(self))                 and decompose:
00142                 if type(value) == type({}):
00143                     set_list = value.keys()
00144                 elif type(value) == type(()):
00145                     set_list = list(value)
00146                 elif type(value) == type(self):
00147                     set_list = value.list()
00148                 else:
00149                     set_list = value
00150                 self.set = set_list
00151             else:
00152                 self.set.append(value)
00153                 
00154     def add_to_set(self, object):
00155         if (type(object) == type([]) or type(object) == type(()) or             type(object) == type({}) or type(object) == type(self))             and self.decompose:
00156             if type(object) == type({}):
00157                 set_list = object.keys()
00158             elif type(object) == type(()):
00159                 set_list = list(object)
00160             elif type(object) == type(self):
00161                 set_list = object.list()
00162             else:
00163                 set_list = object
00164             self.set = self.set + set_list
00165         else:
00166             self.set.append(object)
00167 
00168     def delete_from_set(self, object):
00169         items_to_delete = []
00170         if (type(object) == type([]) or type(object) == type(()) or             type(object) == type({}) or type(object) == type(self))             and self.decompose:
00171             if type(object) == type({}):
00172                 items_to_delete = object.keys()
00173             elif type(object) == type(()):
00174                 items_to_delete = list(object)
00175             elif type(object) == type(self):
00176                 items_to_delete = object.list()
00177             else:
00178                 items_to_delete = object
00179         else:
00180             items_to_delete = [object]
00181         for item in items_to_delete:
00182             if item in self.set:
00183                 ix = self.set.index(item)
00184                 del self.set[ix]
00185             else:
00186                 if self.harsh:
00187                     raise "Error", "item '%s' not in set" % `item`
00188 
00189     def intersection(self, other_set):
00190         self.__check_if_is_a_set(other_set)
00191         new_set = []
00192         if len(self.set) > len(other_set.set):
00193             iter_set = self.set[:]
00194             smaller_set = other_set.set
00195         else:
00196             iter_set = other_set.set[:]
00197             smaller_set = self.set
00198         for element in iter_set:
00199             if element in smaller_set:
00200                 new_set.append(element)
00201         return Set(new_set, decompose=1)
00202 
00203     def union(self, other_set):                             
00204         self.__check_if_is_a_set(other_set)
00205         if len(self.set) > len(other_set.set):
00206             new_set = self.set[:]
00207             iter_set = self.set[:]
00208             smaller_set = other_set.set
00209         else:
00210             new_set = other_set.set[:]
00211             iter_set = other_set.set[:]
00212             smaller_set = self.set
00213         for element in smaller_set:
00214             if element not in iter_set:
00215                 new_set.append(element)
00216         return Set(new_set, decompose=1)                         
00217 
00218     ##
00219     # Returns a set that consists of all elements in self that are
00220     #         not in other_set.
00221     #         
00222     def difference(self, other_set):
00223         self.__check_if_is_a_set(other_set)
00224         new_set = self.set[:]
00225         for element in other_set.set:
00226             try:
00227                 ix = new_set.index(element)
00228                 del new_set[ix]
00229             except:
00230                 pass
00231         return Set(new_set, decompose=1)
00232 
00233     def is_in_set(self, element):
00234         return self.__getitem__(element)
00235 
00236     def is_empty_set(self):
00237         return not len(self.set)
00238 
00239     ##
00240     # Return 1 if self is a subset of other_set, otherwise 
00241     #         return 0.  This is based on the theorem that if A is a 
00242     #         subset of B, then (A union B) = B and (A intersection B) = A.  
00243     #         Here, we get the intersection of self and other_set and see 
00244     #         if it is equal to other_set.
00245     #         
00246     def is_subset_of(self, other_set):
00247         self.__check_if_is_a_set(other_set)
00248         return self.__cmp__(self.intersection(other_set)) == 0
00249 
00250     ##
00251     # Return 1 if self is a proper subset of other_set, otherwise 
00252     #         return 0.
00253     #         
00254     def is_proper_subset_of(self, other_set):
00255         return self.is_subset_of(other_set) and                (len(self.set) != len(other_set.set))
00256 
00257     def list(self):
00258         s = self.set[:]
00259         if self.sorted:
00260             s.sort()
00261         return s
00262 
00263     def __check_if_is_a_set(self, other_set):
00264         if type(other_set) != type(self):
00265             raise "Error", "other_set must be a set object"
00266 
00267     def __len__(self):
00268         return len(self.set)
00269 
00270     ##
00271     # If element is in set, return 1; otherwise return 0.
00272     #         
00273     def __getitem__(self, element):
00274         try:
00275             ix = self.set.index(element)
00276             return 1
00277         except:
00278             return 0
00279 
00280     def __and__(self, other_set):
00281         return self.intersection(other_set)
00282 
00283     def __mul__(self, other_set):
00284         return self.intersection(other_set)
00285 
00286     def __rmul__(self, other_set):
00287         return self.intersection(other_set)
00288 
00289     def __or__(self, other_set):
00290         return self.union(other_set)
00291 
00292     def __add__(self, other_set):
00293         return self.union(other_set)
00294 
00295     def __radd__(self, other_set):
00296         return self.union(other_set)
00297 
00298     def __sub__(self, other_set):
00299         return self.difference(other_set)
00300 
00301     ##
00302     # Returns 0 if self.set is equal to other; otherwise returns 1.
00303     #         
00304     def __cmp__(self, other_set):
00305         if type(other_set) != type(self) or            len(other_set.set) != len(self.set):
00306             return 1
00307         for element in other_set.set:
00308             if element not in other_set.set:
00309                 return 1
00310         return 0
00311 
00312     def __repr__(self):
00313         s = self.set[:]
00314         if self.sorted:
00315             s.sort()
00316         str = `s`
00317         str = "<" + str[1:]
00318         return str[:-1] + ">"
00319 
00320 if __name__ == "__main__":
00321     # Test the Set class
00322     from testset import Test
00323     Test(N=5, use_list_implementation=1)
00324 
00325 

© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved; If you reference this document or any part of this document you must use the citation verbatim (including the link) "© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved."

Notice: This source code contained in this document is NOT open source and is NOT being distributed as open source.

122,241 lines of code and growing...