The CPython documentation provides a selection of useful functions that are built on top of itertools. These have been made available in the **adafruit_itertools_extras** module. not only are these useful, but looking through the implementations is instructive on how iterators and the itertools functions can be used.

##
`all_equal(iterable)`

Returns `True`

if all the elements of `iterable`

are equal to each other.

`>>> all_equal([6, 2*3, 12//2, 4+2])`

`True`

`>>> all_equal([6, 2*3, 12//2, 5, 4+2])`

`False`

##
`dotproduct(vec1, vec2)`

Compute the dot product of two vectors. This is the sum of the products of pairs (one item from each vector)

`>>> dotproduct([1, 2, 3], [1, 2, 3])`

`14`

This is equivalent to (1 * 1) + (2 * 2) + (3 * 3) = 1 + 4 + 9 = 14

##
`first_true(iterable, default=False, pred=None)`

Returns the first *truthy* value in `iterable`

, i.e. the first value `x`

for which `bool(x)`

evaluates to `True`

.

If no true value is found, returns `default`

.

If `pred`

is not `None`

, returns the first item for which `pred(item)`

is true.

`first_true([a,b,c], x)`

is equivalent `a or b or c or x`

`first_true([a,b], x, f)`

is equivalent `a if f(a) else b if f(b) else x`

##
`flatten(iterable_of_iterables)`

Flatten one level of nesting.

`>>> list(flatten(['ABC', 'DEF']))`

`['A', 'B', 'C', 'D', 'E', 'F']`

`>>> list(flatten([[1, [2, 3]], [4, [5], 6]]))`

`[1, [2, 3], 4, [5], 6]`

##
`grouper(iterable, n, fillvalue=None)`

Collect data from `iterable`

into fixed-length chunks of size `n`

. The final chunk will be filled in with `fillvalue`

if iterable has less that a multiple of `n`

elements.

`>>> list(grouper('ABCDEFG', 3, 'x'))`

`[('A', 'B', 'C'), ('D', 'E', 'F'), ('G', 'x', 'x')]`

`>>> list(grouper('ABCDEFG', 2))`

`[('A', 'B'), ('C', 'D'), ('E', 'F'), ('G', None)]`

##
`iter_except(func, exception)`

Call `func`

repeatedly until `exception`

is raised, yielding the result of each call.

`>>> s = [1, 2, 3]`

`>>> s.pop()`

`3`

`>>> s.pop()`

`2`

`>>> s.pop()`

`1`

`>>> s.pop()`

`Traceback (most recent call last):`

`File "", line 1, in `

`IndexError: pop from empty list`

`>>> s = [1, 2, 3]`

`>>> list(iter_except(s.pop, IndexError))`

`[3, 2, 1]`

##
`ncycles(iterable, n)`

Returns an iterable from `n`

copies of the elements from `iterable`

.

`>>> list(ncycles('ABC', 3))`

`['A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C']`

##
` nth(iterable, n, default=None)`

Returns the `nth`

(0-based) item of `iterable`

or a `default`

value (`None`

by default) if `n`

is out of range.

`>>> nth('ABCD', 0)`

`'A'`

`>>> nth('ABCD', 3)`

`'D'`

`>>> nth('ABCD', 4)`

`>>> nth('ABCD', 4, 'Z')`

`'Z'`

##
`padnone(iterable)`

Returns the elements from `iterable`

and then returns `None`

indefinitely.

Useful for emulating the behavior of the built-in `map()`

function.

`take(5, padnone([1, 2, 3]))`

-> `1 2 3 None None`

##
`pairwise(iterable)`

Pair up values in `iterable`

.

`>>> list(pairwise(range(5)))`

`[(0, 1), (1, 2), (2, 3), (3, 4)]`

##
`partition(predicate, iterable)`

Use `predicate`

to partition entries in `iterable`

into false entries and true entries.

`>>> t, f = partition(lambda x: x % 2, range(10))`

`>>> list(t)`

`[0, 2, 4, 6, 8]`

`>>> list(f)`

`[1, 3, 5, 7, 9]`

##
`quantify(iterable, predicate=bool)`

Count the number of elements in `iterable`

for which `predicate`

is `True`

. By default it counts elements `x`

where `bool(x)`

results in `True`

.

`>>> quantify([2, 56, 3, 10, 85], lambda x: x >= 10)`

`3`

##
`repeatfunc(func, times=None, *args)`

Lazily repeat calls to `func`

a number of times set by `times`

with specified arguments (if any). If `times`

is `None`

(the default), call it infinitely. Return values from the function are generated by the resulting iterator.

`>>> take(5, repeatfunc(random.random))`

`[0.777482, 0.718999, 0.953034, 0.388373, 0.982035]`

##
`roundrobin(*iterables)`

Return an iterable created by repeatedly picking a value from each of `iterables`

, in order. As individual iterables are exhausted, they are dropped from the picking.

`>>> list(roundrobin('ABC', 'D', 'EF'))`

`['A', 'D', 'E', 'B', 'F', 'C']`

##
`tabulate(function, start=0)`

Return an iterable populated by applying `function`

to a sequence of consecutive integers, starting at `start`

(defaults to 0).

`>>> take(5, tabulate(lambda x: x * x))`

`[0, 1, 4, 9, 16]`

##
`tail(n, iterable)`

Return an iterator over the last `n`

items of `iterable`

. This only works if `iterable`

is finite.

`>>> list(tail(3, 'ABCDEFG'))`

`['E', 'F', 'G']`