|
|
import operator
|
|
|
|
|
|
class accumulate:
|
|
|
def __init__(self, iterable, func = operator.add):
|
|
|
self.it = iter(iterable)
|
|
|
self._total = None
|
|
|
self.func = func
|
|
|
|
|
|
def __iter__(self):
|
|
|
return self
|
|
|
|
|
|
def __next__(self):
|
|
|
if not self._total:
|
|
|
self._total = next(self.it)
|
|
|
return self._total
|
|
|
else:
|
|
|
element = next(self.it)
|
|
|
try:
|
|
|
self._total = self.func(self._total, element)
|
|
|
except:
|
|
|
raise TypeError("unsupported operand type")
|
|
|
return self._total
|
|
|
|
|
|
## Adapted from:
|
|
|
## https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-34
|
|
|
class chain:
|
|
|
def __init__(self, *iterables):
|
|
|
self._iterables_iter = iter(map(iter, iterables))
|
|
|
# little trick for the first chain.__next__() call
|
|
|
self._cur_iterable_iter = iter([])
|
|
|
|
|
|
def __iter__(self):
|
|
|
return self
|
|
|
|
|
|
def __next__(self):
|
|
|
while True:
|
|
|
try:
|
|
|
return next(self._cur_iterable_iter)
|
|
|
except StopIteration:
|
|
|
self._cur_iterable_iter = next(self._iterables_iter)
|
|
|
|
|
|
@classmethod
|
|
|
def from_iterable(cls, iterable):
|
|
|
for it in iterable:
|
|
|
for element in it:
|
|
|
yield element
|
|
|
|
|
|
class combinations:
|
|
|
def __init__(self, iterable, r):
|
|
|
self.pool = tuple(iterable)
|
|
|
self.n = len(self.pool)
|
|
|
self.r = r
|
|
|
self.indices = list(range(self.r))
|
|
|
self.zero = False
|
|
|
|
|
|
def __iter__(self):
|
|
|
return self
|
|
|
|
|
|
def __next__(self):
|
|
|
if self.r > self.n:
|
|
|
raise StopIteration
|
|
|
if not self.zero:
|
|
|
self.zero = True
|
|
|
return tuple(self.pool[i] for i in self.indices)
|
|
|
else:
|
|
|
try:
|
|
|
for i in reversed(range(self.r)):
|
|
|
if self.indices[i] != i + self.n - self.r:
|
|
|
break
|
|
|
self.indices[i] += 1
|
|
|
for j in range(i+1, self.r):
|
|
|
self.indices[j] = self.indices[j-1] + 1
|
|
|
return tuple(self.pool[i] for i in self.indices)
|
|
|
except:
|
|
|
raise StopIteration
|
|
|
|
|
|
class combinations_with_replacement:
|
|
|
def __init__(self, iterable, r):
|
|
|
self.pool = tuple(iterable)
|
|
|
self.n = len(self.pool)
|
|
|
self.r = r
|
|
|
self.indices = [0] * self.r
|
|
|
self.zero = False
|
|
|
|
|
|
def __iter__(self):
|
|
|
return self
|
|
|
|
|
|
def __next__(self):
|
|
|
if not self.n and self.r:
|
|
|
raise StopIteration
|
|
|
if not self.zero:
|
|
|
self.zero = True
|
|
|
return tuple(self.pool[i] for i in self.indices)
|
|
|
else:
|
|
|
try:
|
|
|
for i in reversed(range(self.r)):
|
|
|
if self.indices[i] != self.n - 1:
|
|
|
break
|
|
|
self.indices[i:] = [self.indices[i] + 1] * (self.r - i)
|
|
|
return tuple(self.pool[i] for i in self.indices)
|
|
|
except:
|
|
|
raise StopIteration
|
|
|
|
|
|
## Literally copied from
|
|
|
##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-63
|
|
|
class compress:
|
|
|
def __init__(self, data, selectors):
|
|
|
self.data = iter(data)
|
|
|
self.selectors = iter(selectors)
|
|
|
|
|
|
def __iter__(self):
|
|
|
return self
|
|
|
|
|
|
def __next__(self):
|
|
|
while True:
|
|
|
next_item = next(self.data)
|
|
|
next_selector = next(self.selectors)
|
|
|
if bool(next_selector):
|
|
|
return next_item
|
|
|
|
|
|
## Adapted from
|
|
|
##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-79
|
|
|
## I mimicked the > python3.1 behavior
|
|
|
class count:
|
|
|
"""
|
|
|
Input is an int or a float. The original Python 3 implementation
|
|
|
includes also complex numbers... but it still is not implemented
|
|
|
in Brython as complex type is NotImplemented
|
|
|
"""
|
|
|
def __init__(self, start = 0, step = 1):
|
|
|
if not isinstance(start, (int, float)):
|
|
|
raise TypeError('a number is required')
|
|
|
self.times = start - step
|
|
|
self.step = step
|
|
|
|
|
|
def __iter__(self):
|
|
|
return self
|
|
|
|
|
|
def __next__(self):
|
|
|
self.times += self.step
|
|
|
return self.times
|
|
|
|
|
|
def __repr__(self):
|
|
|
return 'count(%d)' % (self.times + self.step)
|
|
|
|
|
|
## Literally copied from
|
|
|
##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-112
|
|
|
class cycle:
|
|
|
def __init__(self, iterable):
|
|
|
self._cur_iter = iter(iterable)
|
|
|
self._saved = []
|
|
|
self._must_save = True
|
|
|
|
|
|
def __iter__(self):
|
|
|
return self
|
|
|
|
|
|
def __next__(self):
|
|
|
try:
|
|
|
next_elt = next(self._cur_iter)
|
|
|
if self._must_save:
|
|
|
self._saved.append(next_elt)
|
|
|
except StopIteration:
|
|
|
self._cur_iter = iter(self._saved)
|
|
|
next_elt = next(self._cur_iter)
|
|
|
self._must_save = False
|
|
|
return next_elt
|
|
|
|
|
|
## Literally copied from
|
|
|
##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-149
|
|
|
class dropwhile:
|
|
|
def __init__(self, predicate, iterable):
|
|
|
self._predicate = predicate
|
|
|
self._iter = iter(iterable)
|
|
|
self._dropped = False
|
|
|
|
|
|
def __iter__(self):
|
|
|
return self
|
|
|
|
|
|
def __next__(self):
|
|
|
value = next(self._iter)
|
|
|
if self._dropped:
|
|
|
return value
|
|
|
while self._predicate(value):
|
|
|
value = next(self._iter)
|
|
|
self._dropped = True
|
|
|
return value
|
|
|
|
|
|
## Adapted from
|
|
|
##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-261
|
|
|
class filterfalse:
|
|
|
def __init__(self, predicate, iterable):
|
|
|
# Make sure iterable *IS* iterable
|
|
|
self._iter = iter(iterable)
|
|
|
if predicate is None:
|
|
|
self._predicate = bool
|
|
|
else:
|
|
|
self._predicate = predicate
|
|
|
|
|
|
def __iter__(self):
|
|
|
return self
|
|
|
def __next__(self):
|
|
|
next_elt = next(self._iter)
|
|
|
while True:
|
|
|
if not self._predicate(next_elt):
|
|
|
return next_elt
|
|
|
next_elt = next(self._iter)
|
|
|
|
|
|
class groupby:
|
|
|
# [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B
|
|
|
# [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D
|
|
|
def __init__(self, iterable, key=None):
|
|
|
if key is None:
|
|
|
key = lambda x: x
|
|
|
self.keyfunc = key
|
|
|
self.it = iter(iterable)
|
|
|
self.tgtkey = self.currkey = self.currvalue = object()
|
|
|
def __iter__(self):
|
|
|
return self
|
|
|
def __next__(self):
|
|
|
while self.currkey == self.tgtkey:
|
|
|
self.currvalue = next(self.it) # Exit on StopIteration
|
|
|
self.currkey = self.keyfunc(self.currvalue)
|
|
|
self.tgtkey = self.currkey
|
|
|
return (self.currkey, self._grouper(self.tgtkey))
|
|
|
def _grouper(self, tgtkey):
|
|
|
while self.currkey == tgtkey:
|
|
|
yield self.currvalue
|
|
|
self.currvalue = next(self.it) # Exit on StopIteration
|
|
|
self.currkey = self.keyfunc(self.currvalue)
|
|
|
|
|
|
## adapted from
|
|
|
##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-323
|
|
|
class islice:
|
|
|
def __init__(self, iterable, *args):
|
|
|
s = slice(*args)
|
|
|
self.start, self.stop, self.step = s.start or 0, s.stop, s.step
|
|
|
if not isinstance(self.start, int):
|
|
|
raise ValueError("Start argument must be an integer")
|
|
|
if self.stop != None and not isinstance(self.stop, int):
|
|
|
raise ValueError("Stop argument must be an integer or None")
|
|
|
if self.step is None:
|
|
|
self.step = 1
|
|
|
if self.start<0 or (self.stop != None and self.stop<0
|
|
|
) or self.step<=0:
|
|
|
raise ValueError("indices for islice() must be positive")
|
|
|
self.it = iter(iterable)
|
|
|
self.donext = None
|
|
|
self.cnt = 0
|
|
|
|
|
|
def __iter__(self):
|
|
|
return self
|
|
|
|
|
|
def __next__(self):
|
|
|
nextindex = self.start
|
|
|
if self.stop != None and nextindex >= self.stop:
|
|
|
raise StopIteration
|
|
|
while self.cnt <= nextindex:
|
|
|
nextitem = next(self.it)
|
|
|
self.cnt += 1
|
|
|
self.start += self.step
|
|
|
return nextitem
|
|
|
|
|
|
class permutations:
|
|
|
def __init__(self, iterable, r = None):
|
|
|
self.pool = tuple(iterable)
|
|
|
self.n = len(self.pool)
|
|
|
self.r = self.n if r is None else r
|
|
|
self.indices = list(range(self.n))
|
|
|
self.cycles = list(range(self.n, self.n - self.r, -1))
|
|
|
self.zero = False
|
|
|
self.stop = False
|
|
|
|
|
|
def __iter__(self):
|
|
|
return self
|
|
|
|
|
|
def __next__(self):
|
|
|
indices = self.indices
|
|
|
if self.r > self.n:
|
|
|
raise StopIteration
|
|
|
if not self.zero:
|
|
|
self.zero = True
|
|
|
return tuple(self.pool[i] for i in indices[:self.r])
|
|
|
|
|
|
i = self.r - 1
|
|
|
while i >= 0:
|
|
|
j = self.cycles[i] - 1
|
|
|
if j > 0:
|
|
|
self.cycles[i] = j
|
|
|
indices[i], indices[-j] = indices[-j], indices[i]
|
|
|
return tuple(self.pool[i] for i in indices[:self.r])
|
|
|
self.cycles[i] = len(indices) - i
|
|
|
n1 = len(indices) - 1
|
|
|
assert n1 >= 0
|
|
|
num = indices[i]
|
|
|
for k in range(i, n1):
|
|
|
indices[k] = indices[k+1]
|
|
|
indices[n1] = num
|
|
|
i -= 1
|
|
|
raise StopIteration
|
|
|
|
|
|
# copied from Python documentation on itertools.product
|
|
|
def product(*args, repeat=1):
|
|
|
# product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
|
|
|
# product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
|
|
|
pools = [tuple(pool) for pool in args] * repeat
|
|
|
result = [[]]
|
|
|
for pool in pools:
|
|
|
result = [x+[y] for x in result for y in pool]
|
|
|
for prod in result:
|
|
|
yield tuple(prod)
|
|
|
|
|
|
|
|
|
## adapted from
|
|
|
##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-392
|
|
|
|
|
|
## (Brython)
|
|
|
## renamed to _product : the implementation fails for product('abc', [])
|
|
|
## with CPython 3.x
|
|
|
class _product:
|
|
|
def __init__(self, *args, **kw):
|
|
|
if len(kw) > 1:
|
|
|
raise TypeError("product() takes at most 1 argument (%d given)" %
|
|
|
len(kw))
|
|
|
self.repeat = kw.get('repeat', 1)
|
|
|
if not isinstance(self.repeat, int):
|
|
|
raise TypeError("integer argument expected, got %s" %
|
|
|
type(self.repeat))
|
|
|
self.gears = [x for x in args] * self.repeat
|
|
|
self.num_gears = len(self.gears)
|
|
|
# initialization of indicies to loop over
|
|
|
self.indicies = [(0, len(self.gears[x]))
|
|
|
for x in range(0, self.num_gears)]
|
|
|
self.cont = True
|
|
|
self.zero = False
|
|
|
|
|
|
def roll_gears(self):
|
|
|
# Starting from the end of the gear indicies work to the front
|
|
|
# incrementing the gear until the limit is reached. When the limit
|
|
|
# is reached carry operation to the next gear
|
|
|
should_carry = True
|
|
|
for n in range(0, self.num_gears):
|
|
|
nth_gear = self.num_gears - n - 1
|
|
|
if should_carry:
|
|
|
count, lim = self.indicies[nth_gear]
|
|
|
count += 1
|
|
|
if count == lim and nth_gear == 0:
|
|
|
self.cont = False
|
|
|
if count == lim:
|
|
|
should_carry = True
|
|
|
count = 0
|
|
|
else:
|
|
|
should_carry = False
|
|
|
self.indicies[nth_gear] = (count, lim)
|
|
|
else:
|
|
|
break
|
|
|
|
|
|
def __iter__(self):
|
|
|
return self
|
|
|
|
|
|
def __next__(self):
|
|
|
if self.zero:
|
|
|
raise StopIteration
|
|
|
if self.repeat > 0:
|
|
|
if not self.cont:
|
|
|
raise StopIteration
|
|
|
l = []
|
|
|
for x in range(0, self.num_gears):
|
|
|
index, limit = self.indicies[x]
|
|
|
print('itertools 353',self.gears,x,index)
|
|
|
l.append(self.gears[x][index])
|
|
|
self.roll_gears()
|
|
|
return tuple(l)
|
|
|
elif self.repeat == 0:
|
|
|
self.zero = True
|
|
|
return ()
|
|
|
else:
|
|
|
raise ValueError("repeat argument cannot be negative")
|
|
|
|
|
|
## Literally copied from
|
|
|
##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-441
|
|
|
class repeat:
|
|
|
def __init__(self, obj, times=None):
|
|
|
self._obj = obj
|
|
|
if times is not None:
|
|
|
range(times) # Raise a TypeError
|
|
|
if times < 0:
|
|
|
times = 0
|
|
|
self._times = times
|
|
|
|
|
|
def __iter__(self):
|
|
|
return self
|
|
|
|
|
|
def __next__(self):
|
|
|
# __next__() *need* to decrement self._times when consumed
|
|
|
if self._times is not None:
|
|
|
if self._times <= 0:
|
|
|
raise StopIteration()
|
|
|
self._times -= 1
|
|
|
return self._obj
|
|
|
|
|
|
def __repr__(self):
|
|
|
if self._times is not None:
|
|
|
return 'repeat(%r, %r)' % (self._obj, self._times)
|
|
|
else:
|
|
|
return 'repeat(%r)' % (self._obj,)
|
|
|
|
|
|
def __len__(self):
|
|
|
if self._times == -1 or self._times is None:
|
|
|
raise TypeError("len() of uniszed object")
|
|
|
return self._times
|
|
|
|
|
|
## Adapted from
|
|
|
##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-489
|
|
|
class starmap(object):
|
|
|
def __init__(self, function, iterable):
|
|
|
self._func = function
|
|
|
self._iter = iter(iterable)
|
|
|
|
|
|
def __iter__(self):
|
|
|
return self
|
|
|
|
|
|
def __next__(self):
|
|
|
t = next(self._iter)
|
|
|
return self._func(*t)
|
|
|
|
|
|
## Literally copied from
|
|
|
##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-520
|
|
|
class takewhile(object):
|
|
|
def __init__(self, predicate, iterable):
|
|
|
self._predicate = predicate
|
|
|
self._iter = iter(iterable)
|
|
|
|
|
|
def __iter__(self):
|
|
|
return self
|
|
|
|
|
|
def __next__(self):
|
|
|
value = next(self._iter)
|
|
|
if not self._predicate(value):
|
|
|
raise StopIteration()
|
|
|
return value
|
|
|
|
|
|
## Almost literal from
|
|
|
##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-547
|
|
|
class TeeData(object):
|
|
|
def __init__(self, iterator):
|
|
|
self.data = []
|
|
|
self._iter = iterator
|
|
|
|
|
|
def __getitem__(self, i):
|
|
|
# iterates until 'i' if not done yet
|
|
|
while i>= len(self.data):
|
|
|
self.data.append(next(self._iter))
|
|
|
return self.data[i]
|
|
|
|
|
|
|
|
|
class TeeObject(object):
|
|
|
def __init__(self, iterable=None, tee_data=None):
|
|
|
if tee_data:
|
|
|
self.tee_data = tee_data
|
|
|
self.pos = 0
|
|
|
# <=> Copy constructor
|
|
|
elif isinstance(iterable, TeeObject):
|
|
|
self.tee_data = iterable.tee_data
|
|
|
self.pos = iterable.pos
|
|
|
else:
|
|
|
self.tee_data = TeeData(iter(iterable))
|
|
|
self.pos = 0
|
|
|
|
|
|
def __next__(self):
|
|
|
data = self.tee_data[self.pos]
|
|
|
self.pos += 1
|
|
|
return data
|
|
|
|
|
|
def __iter__(self):
|
|
|
return self
|
|
|
|
|
|
|
|
|
def tee(iterable, n=2):
|
|
|
if isinstance(iterable, TeeObject):
|
|
|
return tuple([iterable] +
|
|
|
[TeeObject(tee_data=iterable.tee_data) for i in range(n - 1)])
|
|
|
tee_data = TeeData(iter(iterable))
|
|
|
return tuple([TeeObject(tee_data=tee_data) for i in range(n)])
|
|
|
|
|
|
class zip_longest:
|
|
|
def __init__(self, *args, fillvalue = None):
|
|
|
self.args = [iter(arg) for arg in args]
|
|
|
self.fillvalue = fillvalue
|
|
|
self.units = len(args)
|
|
|
|
|
|
def __iter__(self):
|
|
|
return self
|
|
|
|
|
|
def __next__(self):
|
|
|
temp = []
|
|
|
nb = 0
|
|
|
for i in range(self.units):
|
|
|
try:
|
|
|
temp.append(next(self.args[i]))
|
|
|
nb += 1
|
|
|
except StopIteration:
|
|
|
temp.append(self.fillvalue)
|
|
|
if nb==0:
|
|
|
raise StopIteration
|
|
|
return tuple(temp)
|
|
|
|