Transducer library for python, inspired by clojure
The performance test sums all even numbers below 1000000.
This library is very slow. Using tranducers, calculating that problem takes twice as much time compared to the version that uses a simple for loop, and filters inside the loop. And 50% slower to version that uses the builtin reduce and the filter iterator of the list.
$ python3 perftest.py
time: 0.315 result 249999500000 algorithm: transduce with filter
time: 0.170 result 249999500000 algorithm: with for loop
time: 0.218 result 249999500000 algorithm: builtin reduce with prefiltered list
This behaves the same way as in the standard library.
map(f, coll)
map
optionally receives multiple collections. In that case it applies f
function for the zip of the collections.
map(f, coll1, coll2, ...)
Supplying only an f
function returns a transducer
map(f)
>>> def add(*args):
... return sum(args)
...
>>> def square(n):
... return n*n
...
>>> def inc(n):
... return n+1
...
>>> from pyducers import map, transduce
>>> list(map(inc, [1, 2, 3]))
[2, 3, 4]
>>> list(map(add, [1, 2], [1, 2]))
[2, 4]
>>> transduce(map(square), add, [1, 2, 3])
14
>>> 1*1 + 2*2 + 3*3
14
This behaves the same way as in the standard library:
filter(f, coll)
Passing only f
to filter returns the transducer
filter(f)
>>> def add(*args):
... return sum(args)
...
>>> def evenp(num):
... return num % 2 == 0
...
>>> from pyducers import filter, transduce
>>>
>>> list(filter(evenp, [1, 2, 3, 4]))
[2, 4]
>>> transduce(filter(evenp), add, [1, 2, 3, 4], 0)
6
compose
function creates a function composition from the provided function. The functions are applied from right to left to the input
Note: when using transducer
on the composition, the composed transducers are applied in the opposite order: from left to right.
compose(f, g, ...)
>>> def add(*args):
... return sum(args)
...
>>> def square(n):
... return n*n
...
>>> def inc(n):
... return n+1
...
>>> def two_times(n):
... return 2*n
...
>>> def evenp(num):
... return num % 2 == 0
...
>>> from pyducers import compose, transduce, map, filter
>>> compose(square, inc)(1)
4
>>> compose(inc, square)(1)
2
>>> compose(inc, square, two_times)(1)
5
>>> compose(two_times, square, inc)(1)
8
>>> transduce(compose(map(square), filter(evenp)), add, [1, 2, 3, 4], 0)
20
tranduce
reduces over a collection with the tranduced reduce function. Initial value can be optionally supplied.
If initial_value
is not provided, it will be generated by calling reduce_function without arguments
: reduce_function()
transduce(transducer, reduce_function, coll, initial_value=None)
>>> def add(*args):
... return sum(args)
...
>>> def evenp(num):
... return num % 2 == 0
...
>>> from pyducers import compose, transduce, map, filter
>>> transduce(filter(evenp), add, [1, 2, 3, 4], 0)
6
sequence
collects the result of the transducer into a collection.
Without transducer, sequence
simply transforms collection into a list.
sequence(coll, xf=None)
>>> def evenp(num):
... return num % 2 == 0
...
>>> from pyducers import filter, sequence
>>> sequence([1, 2])
[1, 2]
>>> sequence([1, 2, 3, 4], filter(evenp))
[2, 4]