Skip to content

Commit d421056

Browse files
committed
-
1 parent 8f15e28 commit d421056

File tree

3 files changed

+162
-92
lines changed

3 files changed

+162
-92
lines changed

source_py3/python_toolbox/math_tools/misc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ def product(numbers):
136136
def is_integer(x):
137137
try:
138138
inted_x = int(x)
139-
except (ValueError, OverflowError):
139+
except (TypeError, ValueError, OverflowError):
140140
return False
141141
return inted_x == x
142142

source_py3/python_toolbox/nifty_collections/bagging.py

Lines changed: 119 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2009-2014 Ram Rachum.,
1+
# Copyright 2009-2014 Ram Rachum.
22
# This program is distributed under the MIT license.
33

44
import 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

343343
class _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

398457
class _OrderedBagMixin(Ordered):
399458
def __repr__(self):

0 commit comments

Comments
 (0)