patternpythonMinor
Functional Pascal triangle in Python (working version)
Viewed 0 times
versionpascalworkingtrianglepythonfunctional
Problem
This is actually a follow-up question of Yet another Pascal triangle in Python written in functional programming pattern, which is put on hold for posting broken code.
Again, this is my implementation of a Pascal program, which is used to print an n-order Pascal triangle. I write it to familiarize myself with Python's Functional Programming Modules. Some changes have been made to get the code work and make it more "functional"
Output:
Please let me know if this piece of code isn't reflecting the essence of functional programming correctly.
Again, this is my implementation of a Pascal program, which is used to print an n-order Pascal triangle. I write it to familiarize myself with Python's Functional Programming Modules. Some changes have been made to get the code work and make it more "functional"
#!/usr/bin/env python3
import operator
from itertools import starmap, tee
def pairwise(iterable):
"""
s -> (s0,s1), (s1,s2), (s2,s3), ...
https://docs.python.org/3/library/itertools.html#itertools-recipes
"""
a, b = tee(iterable)
next(b, None)
return zip(a, b)
def pascal_row(n):
"""
Return a generator that yields the nth row of a Pascal triangle
"""
if n 0:
print_pascal(n-1)
print(list(pascal_row(n)))
print_pascal(10)Output:
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
[1, 7, 21, 35, 35, 21, 7, 1]
[1, 8, 28, 56, 70, 56, 28, 8, 1]
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]Please let me know if this piece of code isn't reflecting the essence of functional programming correctly.
Solution
Your current code calls
However then you can't be returning generators anymore because after one iteration they'll be exhausted and yet the caching will return the same generators repeatedly, so you won't get the right results. This is fine, there wasn't really much use in the generators. It was particularly weird to see
You could return
But really there's no need for all this. The Pythonic way would be:
which is still decently functional.
To be really functional you could ensure that your data structures are immutable and use tuples instead of lists, although it's less pretty:
pascal_row O(n^2) times (put a print inside to see this) through recursion. You don't want to be repeating so much calculation. To cache the results:from functools import lru_cache
@lru_cache(maxsize=None)
def pascal_row(n):However then you can't be returning generators anymore because after one iteration they'll be exhausted and yet the caching will return the same generators repeatedly, so you won't get the right results. This is fine, there wasn't really much use in the generators. It was particularly weird to see
(x for x in [1]).You could return
list(dispatch()) but there's a much better itertools way than successive yielding: chain.return list(chain([1], starmap(operator.add, pairwise(pascal_row(n - 1))), [1]))But really there's no need for all this. The Pythonic way would be:
return [1] + [a + b for a, b in pairwise(pascal_row(n - 1))] + [1]which is still decently functional.
if n
- Make sure the program quickly ends in an error in such a case so that you can find the bug.
Therefore add an assert n == 1 in this case.
This comes out to:
@lru_cache(maxsize=None)
def pascal_row(n):
"""
Return a list that yields the nth row of a Pascal triangle
"""
if n < 2:
assert n == 1
return [1]
else:
return [1] + [a + b for a, b in pairwise(pascal_row(n - 1))] + [1]
In my opinion the recursion in print_pascal` is completely unnecessary and a simple for loop would be much better, but I suppose you want it that way for the exercise.To be really functional you could ensure that your data structures are immutable and use tuples instead of lists, although it's less pretty:
if n < 2:
return (1,)
else:
return (1,) + tuple(a + b for a, b in pairwise(pascal_row(n - 1))) + (1,)Code Snippets
from functools import lru_cache
@lru_cache(maxsize=None)
def pascal_row(n):return list(chain([1], starmap(operator.add, pairwise(pascal_row(n - 1))), [1]))return [1] + [a + b for a, b in pairwise(pascal_row(n - 1))] + [1]@lru_cache(maxsize=None)
def pascal_row(n):
"""
Return a list that yields the nth row of a Pascal triangle
"""
if n < 2:
assert n == 1
return [1]
else:
return [1] + [a + b for a, b in pairwise(pascal_row(n - 1))] + [1]if n < 2:
return (1,)
else:
return (1,) + tuple(a + b for a, b in pairwise(pascal_row(n - 1))) + (1,)Context
StackExchange Code Review Q#158458, answer score: 4
Revisions (0)
No revisions yet.