1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 """
16 This module implements a Set class that uses a List to store the objects
17 in the set.
18 """
19
20 import types
21 from UserList import UserList
22 from mglutil.util import misc
23
24 verbose = False
25
27 """Class to represent Sets of objects stored in a list. There is an
28 implicit order amongst the objects and there can be duplicate objects.
29
30 __getattr__, __setattr__ and __delattr__ have been modified to operate on
31 the list of objects rather than the TreeNodeSet itself, i.e. if atm is an
32 instance of a ListSet a.xxx will not return the member xxx of the object
33 atm but rather a list of the members xxx from each object in the set atm.
34 xxx can be a member of a function that requires no argument.
35
36 Example:
37
38 if atm is an instance of a ListSet:
39 atm.name return the name attribute of each Atom in atm
40 atm.newprop = 7.2 creates a newprop attribute for each Atom in atm
41 with an initial value of 7.2
42 atm.newIndex = range(len(atm)) create a newIndex attribute for each Atom
43 in atm with values 0 for the first atom, 1 for the
44 second, etc...
45 del atm.newIndex
46
47 This class also implement boolean operations on ListSets. These operation
48 overload some operators.
49
50 A uniq() method returns a list with the double removed.
51 A makeUnique() method removes duplicates from list (in place).
52 """
53
54 - def __init__(self, data=None, elementType=None, stringRepr=None,
55 comments="", keywords=[]):
56 if data is not None and len(data)!=0:
57 assert( hasattr(data[0], '__class__') )
58 if elementType is not None:
59 assert( isinstance(data[0], elementType) )
60
61 UserList.__init__(self, data)
62
63 self.__dict__['elementType'] = elementType
64
65 self.stringRepr = stringRepr
66
67 self.__dict__['comments'] = comments
68 self.__dict__['keywords'] = keywords
69 self.selector = None
70
71
73 """set the string representation of this set"""
74 assert type(string) in types.StringTypes
75 self.stringRepr = string
76
77
79 """return the string representation of this set"""
80 return self.stringRepr
81
82
84 """return a copy of the set"""
85 copy = self.__class__(self.data, stringRepr = self.stringRepr)
86 return copy
87
88
90 """add here because __str__ is missing in UserList which creates a pb
91 in jpython"""
92 return str(self.data)
93
94
96 if member[:2]=='__' or member in ['data', 'elementType']:
97 return
98 func = 'if hasattr(o,"%s"): del o.%s' % (member,member)
99 for o in self.data:
100 exec (func)
101
102
104 return iter(self.data)
105
106
108 """Extract the specified member from each objects in the set and
109 returns them as a list
110 """
111
112 if member[:2]=='__':
113 if self.__dict__.has_key(member):
114 return self.__dict__[member]
115 else:
116 raise AttributeError('member %s not found'%member)
117 elif member in ['data', 'elementType', 'stringRepr','comments', 'keywords', 'selector']:
118 return self.__dict__[member]
119 else:
120
121 result = []
122
123 if len(self.data) and callable( getattr(self.data[0], member) ):
124 m = self.data[0].__class__.__dict__[member]
125 for o in self.data:
126 result.append( m(o) )
127
128 else:
129 for o in self.data:
130 result.append( o.__dict__[member] )
131
132
133 return result
134
137
138 - def setAll(self, member, value):
140
142 """Set or create member in each object in this set.
143 If value is a sequence it has to be of the same length as the set.
144 else the new member in each object in the set is set to 'value'
145 """
146
147 if member[:2]=='__':
148 self.__dict__[member] = value
149 elif member in ['data', 'elementType', 'stringRepr', 'comments', 'keywords', 'selector']:
150 self.__dict__[member] = value
151 else:
152 l = len(self.data)
153 if not misc.issequence(value):
154
155
156 for o in self.data: o.__dict__[member] = value
157
158 else:
159
160 if len(value) == 1:
161
162
163 for o in self.data: o.__dict__[member] = value[0]
164
165 else:
166 assert len(self.data) == len(value)
167 for o,v in map(None, self.data, value):
168 setattr(o, member, v)
169
170
171
172
174 assert isinstance(item, self.elementType)
175 if len(self.data)>0 and self.stringRepr and hasattr(item, 'full_name'):
176 self.stringRepr = self.stringRepr+'/+/'+item.full_name()
177 elif hasattr(item, 'full_name'):
178 self.stringRepr = item.full_name()
179 self.data.append(item)
180
182 assert isinstance(item, self.elementType)
183 if len(self.data)>0 and self.stringRepr and hasattr(item, 'full_name'):
184 self.stringRepr = self.stringRepr+'/+/'+item.full_name()
185 elif hasattr(item, 'full_name'):
186 self.stringRepr = item.full_name()
187 self.data.insert(i, item)
188
189 - def pop(self, i=-1):
190 assert isinstance(item, self.elementType)
191 elem = self.data.pop(i)
192 if len(self.data)>0 and self.stringRepr and hasattr(item, 'full_name'):
193 self.stringRepr = self.stringRepr+'/-/'+item.full_name()
194 else:
195 self.stringRepr = None
196 return elem
197
199 assert isinstance(item, self.elementType)
200 self.data.remove(item)
201 if len(self.data)>0 and self.stringRepr and hasattr(item, 'full_name'):
202 self.stringRepr = self.stringRepr+'/-/'+item.full_name()
203 else:
204 self.stringRepr = None
205
207 to_end = False
208 if j>len(self.data)-1:
209 j=len(self.data)
210 if i==0: to_end = True
211
212
213
214 if self.stringRepr:
215
216
217 stringRepr = self.stringRepr+'/&/'
218 ind = self.stringRepr.rfind(':')
219 if to_end:
220 stringRepr = self.stringRepr
221 elif ind > 0:
222 if self.stringRepr[-1]==':':
223
224
225 if i<j-1:
226 stringRepr = self.stringRepr[:ind+1]+'%d-%d'%(i,j-1)
227 else:
228 stringRepr = self.stringRepr[:ind+1]+'%d'%(i)
229 else:
230
231
232 if i<j-1:
233 stringRepr = self.stringRepr+'\\s\\'+'%d-%d'%(i,j-1)
234 else:
235 stringRepr = self.stringRepr+'\\s\\'+'%d'%(i)
236 else:
237 stringRepr = self.data[i].name
238 for m in self.data[i+1:j]:
239 stringRepr += ','+m.name
240 else:
241 if verbose:
242 print 'WARNING long stringRepr due to getslice'
243 stringRepr = ''
244 for obj in self.data[i:j]:
245 stringRepr += obj.full_name()+';'
246 stringRepr = stringRepr[:-1]
247 return self.__class__(self.data[i:j], stringRepr=stringRepr)
248
249
251 if verbose:
252 print 'WARNING long stringRepr due to delslice'
253 del self.data[i:j]
254 stringRepr = ''
255 for obj in self.data:
256 stringRepr += obj.full_name()+';'
257 self.stringRepr = stringRepr[:-1]
258
259
261
262 if len(self.data)==0:
263 return self.__class__([])
264 origStringRepr = self.stringRepr
265 for i in range(i-1):
266 stringRepr += '/+/'+origStringRepr
267 return self.__class__(self.data*n, stringRepr=stringRepr)
268
269
271
272 if len(self.data)==0:
273 return self
274 self.data *= n
275 origStringRepr = self.stringRepr
276 for i in range(i-1):
277 stringRepr += '/+/'+origStringRepr
278 self.stringRepr = stringRepr
279 return self
280
281
283 assert isinstance(right, self.__class__)
284 if len(right.data)==0: return
285 self.data.extend(right.data)
286 if self.stringRepr and right.stringRepr:
287 self.stringRepr = self.stringRepr+'/+/'+right.stringRepr
288 elif verbose:
289 import traceback
290 traceback.print_stack()
291 print 'extending sets with no stringRepr:', repr(self), repr(right)
292
293
295 """See add: overloads += operator"""
296 self.extend(right)
297 return self
298
299
301 """See add: overloads + operator"""
302 assert isinstance(right, self.__class__)
303 if len(right.data)==0: return self.copy()
304 if len(self.data)==0: return right.copy()
305 stringRepr = None
306 if self.stringRepr and right.stringRepr:
307 stringRepr = self.stringRepr+'/+/'+right.stringRepr
308 elif verbose:
309 import traceback
310 traceback.print_stack()
311 print 'adding sets with no stringRepr:', repr(self), repr(right)
312 stringRepr = None
313 return self.__class__( self.data + right.data, stringRepr=stringRepr)
314
315
317 """Union: returns a Set holding objects appearing in either list"""
318
319 assert isinstance(right, self.__class__)
320 stringRepr = None
321 if len(right.data)==0: return self.copy()
322 if len(self.data)==0: return right.copy()
323 if self.stringRepr and right.stringRepr:
324 if self.stringRepr == right.stringRepr:
325 stringRepr = self.stringRepr
326 else:
327 stringRepr = self.stringRepr+'/|/'+right.stringRepr
328 elif verbose:
329 import traceback
330 traceback.print_stack()
331 print 'union of sets with no stringRepr:', repr(self), repr(right)
332 stringRepr = None
333 return self.__class__( misc.uniq(self.data + right.data),
334 stringRepr=stringRepr )
335
336
338 """See union: overloads | operator"""
339 return self.union(right)
340
341
342 - def xor(self, right):
343 """XOR operation: Returns a set made of the elements appearing in first
344 or second set but not in both"""
345
346 assert isinstance(right, self.__class__)
347 if len(right.data)==0: return self.copy()
348 if len(self.data)==0: return right.copy()
349 stringRepr = None
350 l1 = ListSet.__sub__(self, right)
351 l2 = ListSet.__sub__(right, self)
352 if self.stringRepr and right.stringRepr:
353 stringRepr = self.stringRepr+'/^/'+right.stringRepr
354 elif verbose:
355 import traceback
356 traceback.print_stack()
357 print 'xoring sets with no stringRepr:', repr(self), repr(right)
358 stringRepr = None
359 return self.__class__( l1.data + l2.data, stringRepr=stringRepr )
360
361
363 """See union: overloads ^ operator"""
364 return self.xor(right)
365
366
368 """Intersection: returns a Set holding objects appearing in both sets
369 """
370
371 assert isinstance(right, self.__class__)
372 if len(right.data)==0: return self.copy()
373 if len(self.data)==0: return right.copy()
374 l1 = self
375 l2 = right
376 if len(l1.data) > len(right.data):
377 l1 = right
378 l2 = self
379
380 for o in l2.data: o._setFlag = 0
381 for o in l1.data: o._setFlag = 1
382 newlist = filter( lambda x: x._setFlag==1, l2.data )
383 for o in l2.data:
384 if hasattr(o, '_setFlag'):
385 del o._setFlag
386 for o in l1.data:
387 if hasattr(o, '_setFlag'):
388 del o._setFlag
389 stringRepr = None
390 if self.stringRepr and right.stringRepr:
391 stringRepr = self.stringRepr+'/&/'+right.stringRepr
392 elif verbose:
393 import traceback
394 traceback.print_stack()
395 print 'intersecting sets with no stringRepr:', repr(self), repr(right)
396 stringRepr = None
397 return self.__class__(misc.uniq(newlist), stringRepr=stringRepr)
398
399
401 """See inter: overloads & operator"""
402 return self.inter(right)
403
404
406 """Returns a set made of the elements of the first set not appearing
407 in the second set"""
408
409 stringRepr = None
410 assert isinstance(right, self.__class__)
411 if len(right.data)==0: return self.copy()
412 if len(self.data)==0: return self.copy()
413 for o in self.data: o._setFlag = 1
414 for o in right.data: o._setFlag = 0
415 newlist = filter( lambda x: x._setFlag==1, self.data )
416 for o in self.data:
417 if hasattr(o, '_setFlag'):
418 del o._setFlag
419 for o in right.data:
420 if hasattr(o, '_setFlag'):
421 del o._setFlag
422 if self.stringRepr and right.stringRepr:
423 stringRepr = self.stringRepr+'/-/'+right.stringRepr
424 elif verbose:
425 import traceback
426 traceback.print_stack()
427 print 'subtracting sets with no stringRepr:', repr(self), repr(right)
428
429 return self.__class__(newlist, stringRepr=stringRepr)
430
431
433 """See subtract: overloads - operator"""
434 return self.subtract(right)
435
436
438 """removes duplicates from set (in place)"""
439 l = []
440 d = {}
441 for value in self.data:
442 if not d.has_key(id(value)):
443 d[id(value)]=value
444 l.append(value)
445 self.__dict__['data'] = l
446
447
449 set = {}
450
451 return self.__class__([set.setdefault(e,e) for e in self.data if e not in set])
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466