RosettaCodeData/Task/Leonardo-numbers/Python/leonardo-numbers-2.py

77 lines
1.8 KiB
Python

'''Leonardo numbers'''
from functools import (reduce)
from itertools import (islice)
# leo :: Int -> Int -> Int -> Generator [Int]
def leo(L0, L1, delta):
'''A number series of the
Leonardo and Fibonacci pattern,
where L0 and L1 are the first two terms,
and delta = 1 for (L0, L1) == (1, 1)
yields the Leonardo series, while
delta = 0 defines the Fibonacci series.'''
(x, y) = (L0, L1)
while True:
yield x
(x, y) = (y, x + y + delta)
# main :: IO()
def main():
'''Tests.'''
print('\n'.join([
'First 25 Leonardo numbers:',
folded(16)(take(25)(
leo(1, 1, 1)
)),
'',
'First 25 Fibonacci numbers:',
folded(16)(take(25)(
leo(0, 1, 0)
))
]))
# FORMATTING ----------------------------------------------
# folded :: Int -> [a] -> String
def folded(n):
'''Long list folded to rows of n terms each.'''
return lambda xs: '[' + ('\n '.join(
str(ns)[1:-1] for ns in chunksOf(n)(xs)
) + ']')
# GENERIC -------------------------------------------------
# chunksOf :: Int -> [a] -> [[a]]
def chunksOf(n):
'''A series of lists of length n,
subdividing the contents of xs.
Where the length of xs is not evenly divible,
the final list will be shorter than n.'''
return lambda xs: reduce(
lambda a, i: a + [xs[i:n + i]],
range(0, len(xs), n), []
) if 0 < n else []
# take :: Int -> [a] -> [a]
# take :: Int -> String -> String
def take(n):
'''The prefix of xs of length n,
or xs itself if n > length xs.'''
return lambda xs: (
xs[0:n]
if isinstance(xs, list)
else list(islice(xs, n))
)
# MAIN ---
if __name__ == '__main__':
main()