Functional pipeline comes with a number of helper functions to make operating in pipelines cleaner and easier.
tap
The tap
function is a safe entrypoint into a pipeline that calls a given function, and returns
the original value to the pipeline.
This is useful for debugging or for side effects. It creates a deepcopy to call the given function, with, so it is safe to inject this into a pipeline and have it not mutate the pipeline.
>>> from functional_pipeline import pipeline, tap
>>> results = pipeline(
... range(20),
... [
... (filter, lambda x: x % 3 == 0),
... (map, lambda x: x ** 2),
... list,
... tap(print), # will printout the list at this point in the pipeline
... reversed,
... ]
... )
[0, 9, 36, 81, 144, 225, 324]
>>> list(results)
[324, 225, 144, 81, 36, 9, 0]
lens
The lens
helper function is built to drill down into an object to quickly extract the information you
might need.
Lens will try to dig into dictionaries, lists, tuples, and class instances. It takes
a key or keypath (.
separated), and returns a function that will retrieve that
keypath on a given object. If that keypath does not exist, it will return None.
For more complex queries you can use it in conjunction with filter:
>>> from functional_pipeline import pipeline, lens
>>> people = [
... {
... 'first_name': 'John',
... 'last_name': 'Smith',
... 'age': 32,
... 'employment': [{'name': 'McDonalds', 'position': 'Manager'}]
... },
... {
... 'first_name': 'Jane',
... 'last_name': 'Smith',
... 'age': 30,
... 'employment': [{'name': 'BurgerKing', 'position': 'Manager'}]
... },
... {
... 'first_name': 'Billy',
... 'last_name': 'Bob',
... 'age': 55,
... 'employment': [{'name': 'Microsoft', 'position': 'Programmer'}]
... },
... ]
>>> first_names = pipeline(
... people,
... [
... (map, lens('first_name')),
... list,
... ]
... )
>>> first_names
['John', 'Jane', 'Billy']
>>> unique_last_names = pipeline(
... people,
... [
... (map, lens('last_name')),
... set,
... list,
... sorted,
... ]
... )
>>> unique_last_names
['Bob', 'Smith']
>>> names_of_companies_current_employed = pipeline(
... people,
... [
... (map, lens('employment.0.name')),
... list,
... ]
... )
>>> names_of_companies_current_employed
['McDonalds', 'BurgerKing', 'Microsoft']
>>> first_name_of_managers = pipeline(
... people,
... [
... (filter, lambda person: lens('employment.0.position')(person) == 'Manager'),
... (map, lens('first_name')),
... list,
... ]
... )
>>> first_name_of_managers
['John', 'Jane']
sort
Helper method wrapping sorted
that allows for the keyfunc=
and reversed=
attributes to be passed in
>>> from functional_pipeline import pipeline, sort
>>> coordinates = [
... (2, 3),
... (5, 7),
... (-2, 1),
... (3, 2),
... ]
>>> sorted_positive_cooridates = pipeline(
... coordinates,
... [
... (filter, lambda x: x[0] > 0),
... sort(lambda x: x[0]),
... (map, lambda x: f"x={x[0]},y={x[1]}"),
... list,
... ]
... )
>>> sorted_positive_cooridates
['x=2,y=3', 'x=3,y=2', 'x=5,y=7']
take
Take is a list/generator agnostic way of taking the first n elements from a sequence.
>>> from functional_pipeline import pipeline, take
>>> five_from_range = pipeline(
... range(100),
... [
... take(5)
... ]
... )
>>> list(five_from_range) # until list() is called, this is still a generator. Take is lazy
[0, 1, 2, 3, 4]
>>> two_from_list = pipeline(
... [1,2,3],
... [
... take(2),
... list,
... ]
... )
>>> list(two_from_list)
[1, 2]
clone
Clone is a helper function that takes an object and returns a tuple of two of the object.
>>> from functional_pipeline import pipeline, clone
>>> words = ['racecar', 'palindrome', 'lol', 'python', 'wow']
>>> palindromes = pipeline(
... words,
... [
... (map, clone),
... (map, lambda x: (x[0], x[1][::-1])),
... (filter, lambda x: x[0] == x[1]),
... (map, lambda x: x[1]),
... list,
... ]
... )
>>> palindromes
['racecar', 'lol', 'wow']
index
The index function is a safe get of an index of a sequence
>>> from functional_pipeline import pipeline, index
>>> success = pipeline(
... [1, 2, 3],
... [
... index(1),
... ]
... )
>>> success
2
>>> safe = pipeline(
... [1, 2, 3],
... [
... index(20),
... ]
... )
>>> safe
contains
Predicate that wraps the in
keyword.
>>> from functional_pipeline import pipeline, contains
>>> words = ['this', 'that', 'other', 'foo', 'bar']
>>> words_with_t = pipeline(
... words,
... [
... (filter, contains('t')),
... list,
... ]
... )
>>> words_with_t
['this', 'that', 'other']
join
Wrapper around str.join()
.
>>> from functional_pipeline import pipeline, join
>>> piped_evens = pipeline(
... range(20),
... [
... (filter, lambda x: x % 2 == 0),
... (map, str),
... join('|'),
... ]
... )
>>> piped_evens
'0|2|4|6|8|10|12|14|16|18'
flatten
Flatten an iterable of iterables into a single iterable.
Will return a generator of the flattened state.
>>> from functional_pipeline import pipeline, flatten
>>> nested_ranges = (range(n) for n in range(5))
>>> flat = pipeline(
... nested_ranges,
... [
... flatten,
... list,
... ]
... )
>>> flat
[0, 0, 1, 0, 1, 2, 0, 1, 2, 3]
not_none
Shorthand for a predicate that checks if obj is not None
>>> from functional_pipeline import pipeline, not_none
>>> stream = [1, None, 2, 3, 4, None, 5, 6]
>>> output = pipeline(
... stream,
... [
... (filter, not_none),
... list,
... ]
... )
>>> output
[1, 2, 3, 4, 5, 6]
flatmap
A shorthand for map -> flatten.
New in 0.3.0
>>> from functional_pipeline import pipeline, flatmap
>>> results = pipeline(
... [3, 4, 2],
... [
... (flatmap, range),
... list,
... ]
... )
>>> results
[0, 1, 2, 0, 1, 2, 3, 0, 1]
zipmap
Takes a tuple of functions, and applies a list of tuples to them, returning the tuple outputs.
New in 0.3.0
>>> from functional_pipeline import pipeline, zipmap
>>> def double(x):
... return x * 2
>>> def square(x):
... return x ** 2
>>> results = pipeline(
... 5,
... [
... range,
... enumerate,
... (zipmap, (double, square)),
... list,
... ]
... )
>>> results
[(0, 0), (2, 1), (4, 4), (6, 9), (8, 16)]
foldl
A alias for functools.reduce
with the order of arguments fixed to be more inline with function programming standards.
New in 0.4.0
>>> from functional_pipeline import pipeline, foldl
>>> from operator import add
>>> pipeline(10, [range, (foldl, add, 0)])
45
>>> pipeline([], [(foldl, add, 0)])
0
>>> pipeline([], [iter, (foldl, add, 0)])
0
>>> pipeline(3, [range, (foldl, max, 5)])
5
scanl
An alias for itertools.accumulate
with the order of the arguments fixed to be more inline with functional programming standards.
New in 0.5.0
>>> from functional_pipeline import pipeline, scanl
>>> from operator import add
>>> pipeline(5, [range, (scanl, add, 0), list])
[0, 0, 1, 3, 6, 10]
>>> pipeline(4, [range, (scanl, max, 5), list])
[5, 5, 5, 5, 5]
>>> pipeline([1, 2, 3], [(scanl, lambda x, y: 2*x + y, 4), list])
[4, 9, 20, 43]
filter_where
This is a shortcut function that allows for filter and lens to be combined with a comparison operator, so
filter_where('data.name', 'John)
is functionally equivalent to (filter , lambda x: lens('data.name')(x) == 'John')
New in 0.6.0
It works on lists, dictionaries, and objects since it uses lens()
as the operator for the first. It also has
a default comparator argument that is defaulted to operator.eq
; This allows for filtering where Greater or Less Than.
>>> from functional_pipeline import pipeline, filter_where
>>> dataset = [
... {'name': 'John', 'meta': {'age': 30, 'gender': 'M'}},
... {'name': 'Jane', 'meta': {'age': 43, 'gender': 'F'}},
... {'name': 'James', 'meta': {'age': 22, 'gender': 'M'}},
... {'name': 'Mary', 'meta': {'age': 14, 'gender': 'f'}},
... ]
>>> pipeline(dataset, [filter_where('meta.gender', 'M'), list])
[{'name': 'John', 'meta': {'age': 30, 'gender': 'M'}}, {'name': 'James', 'meta': {'age': 22, 'gender': 'M'}}]
>>> from operator import ge
>>> pipeline(dataset, [filter_where('meta.age', 30, ge), list])
[{'name': 'John', 'meta': {'age': 30, 'gender': 'M'}}, {'name': 'Jane', 'meta': {'age': 43, 'gender': 'F'}}]