123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577 |
- """Imported from the recipes section of the itertools documentation.
- All functions taken from the recipes section of the itertools library docs
- [1]_.
- Some backward-compatible usability improvements have been made.
- .. [1] http://docs.python.org/library/itertools.html#recipes
- """
- from collections import deque
- from itertools import (
- chain, combinations, count, cycle, groupby, islice, repeat, starmap, tee
- )
- import operator
- from random import randrange, sample, choice
- from six import PY2
- from six.moves import filter, filterfalse, map, range, zip, zip_longest
- __all__ = [
- 'accumulate',
- 'all_equal',
- 'consume',
- 'dotproduct',
- 'first_true',
- 'flatten',
- 'grouper',
- 'iter_except',
- 'ncycles',
- 'nth',
- 'nth_combination',
- 'padnone',
- 'pairwise',
- 'partition',
- 'powerset',
- 'prepend',
- 'quantify',
- 'random_combination_with_replacement',
- 'random_combination',
- 'random_permutation',
- 'random_product',
- 'repeatfunc',
- 'roundrobin',
- 'tabulate',
- 'tail',
- 'take',
- 'unique_everseen',
- 'unique_justseen',
- ]
- def accumulate(iterable, func=operator.add):
- """
- Return an iterator whose items are the accumulated results of a function
- (specified by the optional *func* argument) that takes two arguments.
- By default, returns accumulated sums with :func:`operator.add`.
- >>> list(accumulate([1, 2, 3, 4, 5])) # Running sum
- [1, 3, 6, 10, 15]
- >>> list(accumulate([1, 2, 3], func=operator.mul)) # Running product
- [1, 2, 6]
- >>> list(accumulate([0, 1, -1, 2, 3, 2], func=max)) # Running maximum
- [0, 1, 1, 2, 3, 3]
- This function is available in the ``itertools`` module for Python 3.2 and
- greater.
- """
- it = iter(iterable)
- try:
- total = next(it)
- except StopIteration:
- return
- else:
- yield total
- for element in it:
- total = func(total, element)
- yield total
- def take(n, iterable):
- """Return first *n* items of the iterable as a list.
- >>> take(3, range(10))
- [0, 1, 2]
- >>> take(5, range(3))
- [0, 1, 2]
- Effectively a short replacement for ``next`` based iterator consumption
- when you want more than one item, but less than the whole iterator.
- """
- return list(islice(iterable, n))
- def tabulate(function, start=0):
- """Return an iterator over the results of ``func(start)``,
- ``func(start + 1)``, ``func(start + 2)``...
- *func* should be a function that accepts one integer argument.
- If *start* is not specified it defaults to 0. It will be incremented each
- time the iterator is advanced.
- >>> square = lambda x: x ** 2
- >>> iterator = tabulate(square, -3)
- >>> take(4, iterator)
- [9, 4, 1, 0]
- """
- return map(function, count(start))
- def tail(n, iterable):
- """Return an iterator over the last *n* items of *iterable*.
- >>> t = tail(3, 'ABCDEFG')
- >>> list(t)
- ['E', 'F', 'G']
- """
- return iter(deque(iterable, maxlen=n))
- def consume(iterator, n=None):
- """Advance *iterable* by *n* steps. If *n* is ``None``, consume it
- entirely.
- Efficiently exhausts an iterator without returning values. Defaults to
- consuming the whole iterator, but an optional second argument may be
- provided to limit consumption.
- >>> i = (x for x in range(10))
- >>> next(i)
- 0
- >>> consume(i, 3)
- >>> next(i)
- 4
- >>> consume(i)
- >>> next(i)
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- StopIteration
- If the iterator has fewer items remaining than the provided limit, the
- whole iterator will be consumed.
- >>> i = (x for x in range(3))
- >>> consume(i, 5)
- >>> next(i)
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- StopIteration
- """
- # Use functions that consume iterators at C speed.
- if n is None:
- # feed the entire iterator into a zero-length deque
- deque(iterator, maxlen=0)
- else:
- # advance to the empty slice starting at position n
- next(islice(iterator, n, n), None)
- def nth(iterable, n, default=None):
- """Returns the nth item or a default value.
- >>> l = range(10)
- >>> nth(l, 3)
- 3
- >>> nth(l, 20, "zebra")
- 'zebra'
- """
- return next(islice(iterable, n, None), default)
- def all_equal(iterable):
- """
- Returns ``True`` if all the elements are equal to each other.
- >>> all_equal('aaaa')
- True
- >>> all_equal('aaab')
- False
- """
- g = groupby(iterable)
- return next(g, True) and not next(g, False)
- def quantify(iterable, pred=bool):
- """Return the how many times the predicate is true.
- >>> quantify([True, False, True])
- 2
- """
- return sum(map(pred, iterable))
- def padnone(iterable):
- """Returns the sequence of elements and then returns ``None`` indefinitely.
- >>> take(5, padnone(range(3)))
- [0, 1, 2, None, None]
- Useful for emulating the behavior of the built-in :func:`map` function.
- See also :func:`padded`.
- """
- return chain(iterable, repeat(None))
- def ncycles(iterable, n):
- """Returns the sequence elements *n* times
- >>> list(ncycles(["a", "b"], 3))
- ['a', 'b', 'a', 'b', 'a', 'b']
- """
- return chain.from_iterable(repeat(tuple(iterable), n))
- def dotproduct(vec1, vec2):
- """Returns the dot product of the two iterables.
- >>> dotproduct([10, 10], [20, 20])
- 400
- """
- return sum(map(operator.mul, vec1, vec2))
- def flatten(listOfLists):
- """Return an iterator flattening one level of nesting in a list of lists.
- >>> list(flatten([[0, 1], [2, 3]]))
- [0, 1, 2, 3]
- See also :func:`collapse`, which can flatten multiple levels of nesting.
- """
- return chain.from_iterable(listOfLists)
- def repeatfunc(func, times=None, *args):
- """Call *func* with *args* repeatedly, returning an iterable over the
- results.
- If *times* is specified, the iterable will terminate after that many
- repetitions:
- >>> from operator import add
- >>> times = 4
- >>> args = 3, 5
- >>> list(repeatfunc(add, times, *args))
- [8, 8, 8, 8]
- If *times* is ``None`` the iterable will not terminate:
- >>> from random import randrange
- >>> times = None
- >>> args = 1, 11
- >>> take(6, repeatfunc(randrange, times, *args)) # doctest:+SKIP
- [2, 4, 8, 1, 8, 4]
- """
- if times is None:
- return starmap(func, repeat(args))
- return starmap(func, repeat(args, times))
- def pairwise(iterable):
- """Returns an iterator of paired items, overlapping, from the original
- >>> take(4, pairwise(count()))
- [(0, 1), (1, 2), (2, 3), (3, 4)]
- """
- a, b = tee(iterable)
- next(b, None)
- return zip(a, b)
- def grouper(n, iterable, fillvalue=None):
- """Collect data into fixed-length chunks or blocks.
- >>> list(grouper(3, 'ABCDEFG', 'x'))
- [('A', 'B', 'C'), ('D', 'E', 'F'), ('G', 'x', 'x')]
- """
- args = [iter(iterable)] * n
- return zip_longest(fillvalue=fillvalue, *args)
- def roundrobin(*iterables):
- """Yields an item from each iterable, alternating between them.
- >>> list(roundrobin('ABC', 'D', 'EF'))
- ['A', 'D', 'E', 'B', 'F', 'C']
- This function produces the same output as :func:`interleave_longest`, but
- may perform better for some inputs (in particular when the number of
- iterables is small).
- """
- # Recipe credited to George Sakkis
- pending = len(iterables)
- if PY2:
- nexts = cycle(iter(it).next for it in iterables)
- else:
- nexts = cycle(iter(it).__next__ for it in iterables)
- while pending:
- try:
- for next in nexts:
- yield next()
- except StopIteration:
- pending -= 1
- nexts = cycle(islice(nexts, pending))
- def partition(pred, iterable):
- """
- Returns a 2-tuple of iterables derived from the input iterable.
- The first yields the items that have ``pred(item) == False``.
- The second yields the items that have ``pred(item) == True``.
- >>> is_odd = lambda x: x % 2 != 0
- >>> iterable = range(10)
- >>> even_items, odd_items = partition(is_odd, iterable)
- >>> list(even_items), list(odd_items)
- ([0, 2, 4, 6, 8], [1, 3, 5, 7, 9])
- """
- # partition(is_odd, range(10)) --> 0 2 4 6 8 and 1 3 5 7 9
- t1, t2 = tee(iterable)
- return filterfalse(pred, t1), filter(pred, t2)
- def powerset(iterable):
- """Yields all possible subsets of the iterable.
- >>> list(powerset([1, 2, 3]))
- [(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
- :func:`powerset` will operate on iterables that aren't :class:`set`
- instances, so repeated elements in the input will produce repeated elements
- in the output. Use :func:`unique_everseen` on the input to avoid generating
- duplicates:
- >>> seq = [1, 1, 0]
- >>> list(powerset(seq))
- [(), (1,), (1,), (0,), (1, 1), (1, 0), (1, 0), (1, 1, 0)]
- >>> from more_itertools import unique_everseen
- >>> list(powerset(unique_everseen(seq)))
- [(), (1,), (0,), (1, 0)]
- """
- s = list(iterable)
- return chain.from_iterable(combinations(s, r) for r in range(len(s) + 1))
- def unique_everseen(iterable, key=None):
- """
- Yield unique elements, preserving order.
- >>> list(unique_everseen('AAAABBBCCDAABBB'))
- ['A', 'B', 'C', 'D']
- >>> list(unique_everseen('ABBCcAD', str.lower))
- ['A', 'B', 'C', 'D']
- Sequences with a mix of hashable and unhashable items can be used.
- The function will be slower (i.e., `O(n^2)`) for unhashable items.
- """
- seenset = set()
- seenset_add = seenset.add
- seenlist = []
- seenlist_add = seenlist.append
- if key is None:
- for element in iterable:
- try:
- if element not in seenset:
- seenset_add(element)
- yield element
- except TypeError:
- if element not in seenlist:
- seenlist_add(element)
- yield element
- else:
- for element in iterable:
- k = key(element)
- try:
- if k not in seenset:
- seenset_add(k)
- yield element
- except TypeError:
- if k not in seenlist:
- seenlist_add(k)
- yield element
- def unique_justseen(iterable, key=None):
- """Yields elements in order, ignoring serial duplicates
- >>> list(unique_justseen('AAAABBBCCDAABBB'))
- ['A', 'B', 'C', 'D', 'A', 'B']
- >>> list(unique_justseen('ABBCcAD', str.lower))
- ['A', 'B', 'C', 'A', 'D']
- """
- return map(next, map(operator.itemgetter(1), groupby(iterable, key)))
- def iter_except(func, exception, first=None):
- """Yields results from a function repeatedly until an exception is raised.
- Converts a call-until-exception interface to an iterator interface.
- Like ``iter(func, sentinel)``, but uses an exception instead of a sentinel
- to end the loop.
- >>> l = [0, 1, 2]
- >>> list(iter_except(l.pop, IndexError))
- [2, 1, 0]
- """
- try:
- if first is not None:
- yield first()
- while 1:
- yield func()
- except exception:
- pass
- def first_true(iterable, default=None, pred=None):
- """
- Returns the first true value in the iterable.
- If no true value is found, returns *default*
- If *pred* is not None, returns the first item for which
- ``pred(item) == True`` .
- >>> first_true(range(10))
- 1
- >>> first_true(range(10), pred=lambda x: x > 5)
- 6
- >>> first_true(range(10), default='missing', pred=lambda x: x > 9)
- 'missing'
- """
- return next(filter(pred, iterable), default)
- def random_product(*args, **kwds):
- """Draw an item at random from each of the input iterables.
- >>> random_product('abc', range(4), 'XYZ') # doctest:+SKIP
- ('c', 3, 'Z')
- If *repeat* is provided as a keyword argument, that many items will be
- drawn from each iterable.
- >>> random_product('abcd', range(4), repeat=2) # doctest:+SKIP
- ('a', 2, 'd', 3)
- This equivalent to taking a random selection from
- ``itertools.product(*args, **kwarg)``.
- """
- pools = [tuple(pool) for pool in args] * kwds.get('repeat', 1)
- return tuple(choice(pool) for pool in pools)
- def random_permutation(iterable, r=None):
- """Return a random *r* length permutation of the elements in *iterable*.
- If *r* is not specified or is ``None``, then *r* defaults to the length of
- *iterable*.
- >>> random_permutation(range(5)) # doctest:+SKIP
- (3, 4, 0, 1, 2)
- This equivalent to taking a random selection from
- ``itertools.permutations(iterable, r)``.
- """
- pool = tuple(iterable)
- r = len(pool) if r is None else r
- return tuple(sample(pool, r))
- def random_combination(iterable, r):
- """Return a random *r* length subsequence of the elements in *iterable*.
- >>> random_combination(range(5), 3) # doctest:+SKIP
- (2, 3, 4)
- This equivalent to taking a random selection from
- ``itertools.combinations(iterable, r)``.
- """
- pool = tuple(iterable)
- n = len(pool)
- indices = sorted(sample(range(n), r))
- return tuple(pool[i] for i in indices)
- def random_combination_with_replacement(iterable, r):
- """Return a random *r* length subsequence of elements in *iterable*,
- allowing individual elements to be repeated.
- >>> random_combination_with_replacement(range(3), 5) # doctest:+SKIP
- (0, 0, 1, 2, 2)
- This equivalent to taking a random selection from
- ``itertools.combinations_with_replacement(iterable, r)``.
- """
- pool = tuple(iterable)
- n = len(pool)
- indices = sorted(randrange(n) for i in range(r))
- return tuple(pool[i] for i in indices)
- def nth_combination(iterable, r, index):
- """Equivalent to ``list(combinations(iterable, r))[index]``.
- The subsequences of *iterable* that are of length *r* can be ordered
- lexicographically. :func:`nth_combination` computes the subsequence at
- sort position *index* directly, without computing the previous
- subsequences.
- """
- pool = tuple(iterable)
- n = len(pool)
- if (r < 0) or (r > n):
- raise ValueError
- c = 1
- k = min(r, n - r)
- for i in range(1, k + 1):
- c = c * (n - k + i) // i
- if index < 0:
- index += c
- if (index < 0) or (index >= c):
- raise IndexError
- result = []
- while r:
- c, n, r = c * r // n, n - 1, r - 1
- while index >= c:
- index -= c
- c, n = c * (n - r) // n, n - 1
- result.append(pool[-1 - n])
- return tuple(result)
- def prepend(value, iterator):
- """Yield *value*, followed by the elements in *iterator*.
- >>> value = '0'
- >>> iterator = ['1', '2', '3']
- >>> list(prepend(value, iterator))
- ['0', '1', '2', '3']
- To prepend multiple values, see :func:`itertools.chain`.
- """
- return chain([value], iterator)
|