1- # Copyright 2009-2014 Ram Rachum.,
1+ # Copyright 2009-2014 Ram Rachum.
22# This program is distributed under the MIT license.
33
44import operator
@@ -117,36 +117,6 @@ def elements(self):
117117 def __contains__ (self , item ):
118118 return (self [item ] >= 1 )
119119
120-
121- def __add__ (self , other ):
122- '''
123- Add counts from two bags.
124-
125- >>> FrozenBag('abbb') + FrozenBag('bcc')
126- FrozenBag({'b': 4, 'c': 2, 'a': 1})
127-
128- '''
129- if not isinstance (other , _BaseBagMixin ):
130- return NotImplemented
131- return type (self )(self ._dict_type (
132- (key , self [key ] + other [key ])
133- for key in set (self ) | set (other ))
134- )
135-
136- def __sub__ (self , other ):
137- '''
138- Subtract count, but keep only results with positive counts.
139-
140- >>> FrozenBag('abbbc') - FrozenBag('bccd')
141- FrozenBag({'b': 2, 'a': 1})
142-
143- '''
144- if not isinstance (other , _BaseBagMixin ):
145- return NotImplemented
146- return type (self )(self ._dict_type (
147- (key , max (self [key ] - other [key ], 0 )) for key in self )
148- )
149-
150120 def __or__ (self , other ):
151121 '''
152122 Get the maximum of value in either of the input bags.
@@ -178,48 +148,65 @@ def __and__(self, other):
178148 )
179149
180150
151+ def __add__ (self , other ):
152+ if not isinstance (other , _BaseBagMixin ):
153+ return NotImplemented
154+ return type (self )(self ._dict_type (
155+ (key , self [key ] + other [key ])
156+ for key in set (self ) | set (other ))
157+ )
158+
159+ def __sub__ (self , other ):
160+ '''
161+ blocktododoc
162+ Negative counts are truncated to zero.
163+ '''
164+ if not isinstance (other , _BaseBagMixin ):
165+ return NotImplemented
166+ return type (self )(self ._dict_type (
167+ (key , max (self [key ] - other [key ], 0 )) for key in self )
168+ )
169+
181170 def __mul__ (self , other ):
182171 if not math_tools .is_integer (other ):
183172 return NotImplemented
184173 return type (self )(self ._dict_type ((key , count * other ) for
185174 key , count in self .items ()))
186- def __pow__ (self , other , modulo = None ):
187- if not math_tools .is_integer (other ):
188- return NotImplemented
189- if modulo is None :
190- return type (self )(self ._dict_type ((key , count ** other ) for
191- key , count in self .items ()))
192- else :
193- return type (self )(self ._dict_type (
194- (key , pow (count , other , modulo )) for
195- key , count in self .items ())
196- )
197- def __mod__ (self , other ):
198- if math_tools .is_integer (other ):
199- return (
200- type (self )(self ._dict_type ((key , count % other ) for
201- key , count in self .items ())),
202- )
203- elif isinstance (other , _BaseBagMixin ):
204- return divmod (self , other )[1 ]
205- else :
206- return NotImplemented
207175 def __floordiv__ (self , other ):
208176 if math_tools .is_integer (other ):
209177 return (
210178 type (self )(self ._dict_type ((key , count // other ) for
211- key , count in self .items ())),
179+ key , count in self .items ()))
212180 )
213181 elif isinstance (other , _BaseBagMixin ):
214182 for key in other :
215183 if key not in self :
216184 assert other [key ] >= 1
217185 return (0 , self .copy () if
218186 isinstance (self , collections .Hashable ) else self )
219- return min (self [key ] // other [key ] for key in self )
187+ division_results = []
188+ for key in self :
189+ if other [key ] >= 1 :
190+ division_results .append (self [key ] // other [key ])
191+ if division_results :
192+ return min (division_results )
193+ else :
194+ raise ZeroDivisionError
220195
221196 else :
222197 return NotImplemented
198+
199+ def __mod__ (self , other ):
200+ if math_tools .is_integer (other ):
201+ return (
202+ type (self )(self ._dict_type ((key , count % other ) for
203+ key , count in self .items ())),
204+ )
205+ elif isinstance (other , _BaseBagMixin ):
206+ return divmod (self , other )[1 ]
207+ else :
208+ return NotImplemented
209+
223210 def __divmod__ (self , other ):
224211 if math_tools .is_integer (other ):
225212 return (
@@ -243,6 +230,19 @@ def __divmod__(self, other):
243230
244231 else :
245232 return NotImplemented
233+
234+ def __pow__ (self , other , modulo = None ):
235+ if not math_tools .is_integer (other ):
236+ return NotImplemented
237+ if modulo is None :
238+ return type (self )(self ._dict_type ((key , count ** other ) for
239+ key , count in self .items ()))
240+ else :
241+ return type (self )(self ._dict_type (
242+ (key , pow (count , other , modulo )) for
243+ key , count in self .items ())
244+ )
245+
246246 __bool__ = lambda self : any (True for element in self .elements ())
247247
248248
@@ -341,19 +341,13 @@ def __repr__(self):
341341
342342
343343class _MutableBagMixin (_BaseBagMixin ):
344- # blocktodo: ensure all mutable methods, like __iadd__ and everything
345-
346344 def __setitem__ (self , i , count ):
347345 try :
348346 super ().__setitem__ (i , _process_count (count ))
349347 except _ZeroCountAttempted :
350348 del self [i ]
351349
352350
353- def __imod__ (self , modulo ):
354- for key in tuple (self .keys ()):
355- self [key ] %= modulo
356- return self
357351
358352 def setdefault (self , key , default ):
359353 current_count = self [key ]
@@ -393,7 +387,72 @@ def __repr__(self):
393387 self ._dict if self ._dict else ''
394388 )
395389
390+ def __ior__ (self , other ):
391+ '''
392+ Get the maximum of value in either of the input bags.
393+
394+ >>> FrozenBag('abbb') | FrozenBag('bcc')
395+ FrozenBag({'b': 3, 'c': 2, 'a': 1})
396+
397+ '''
398+ if not isinstance (other , _BaseBagMixin ):
399+ return NotImplemented
400+ for key , other_count in other .items ():
401+ self [key ] = max (self [key ], other_count )
396402
403+ def __iand__ (self , other ):
404+ '''
405+
406+ Get the minimum of corresponding counts.
407+ >>> FrozenBag('abbb') & FrozenBag('bcc')
408+ FrozenBag({'b': 1})
409+
410+ '''
411+ if not isinstance (other , _BaseBagMixin ):
412+ return NotImplemented
413+ for key , count in self .items ():
414+ self [key ] = min (count , other [key ])
415+
416+ def __iadd__ (self , other ):
417+ if not isinstance (other , _BaseBagMixin ):
418+ return NotImplemented
419+ for key , other_count in other .items ():
420+ self [key ] += other_count
421+
422+ def __isub__ (self , other ):
423+ '''
424+ blocktododoc
425+ Negative counts are truncated to zero.
426+ '''
427+ if not isinstance (other , _BaseBagMixin ):
428+ return NotImplemented
429+ for key , other_count in other .items ():
430+ self [key ] = max (self [key ] - other_count , 0 )
431+
432+
433+ def __imul__ (self , other ):
434+ if not math_tools .is_integer (other ):
435+ return NotImplemented
436+ for key in self :
437+ self [key ] *= other
438+
439+ def __ifloordiv__ (self , other ):
440+ if not math_tools .is_integer (other ):
441+ return NotImplemented
442+ for key in self :
443+ self [key ] //= other
444+
445+ def __imod__ (self , other ):
446+ if not math_tools .is_integer (other ):
447+ return NotImplemented
448+ for key in self :
449+ self [key ] %= other
450+
451+ def __ipow__ (self , other , modulo = None ):
452+ if not math_tools .is_integer (other ):
453+ return NotImplemented
454+ for key in self :
455+ self [key ] = power (self [key ], other , modulo )
397456
398457class _OrderedBagMixin (Ordered ):
399458 def __repr__ (self ):
0 commit comments