RosettaCodeData/Task/Forward-difference/Python/forward-difference-2.py

94 lines
2.0 KiB
Python

'''Forward difference'''
from itertools import islice
from operator import sub
# forwardDifference :: Num a => [a] -> [a]
def forwardDifference(xs):
'''1st order forward difference of xs.
'''
return [sub(*x) for x in zip(xs[1:], xs)]
# nthForwardDifference :: Num a => [a] -> Int -> [a]
def nthForwardDifference(xs):
'''Nth order forward difference of xs.
'''
return index(iterate(forwardDifference)(xs))
# ------------------------- TEST --------------------------
# main :: IO ()
def main():
'''Nth order forward difference.'''
xs = [90, 47, 58, 29, 22, 32, 55, 5, 55, 73]
print('9th order forward difference of:')
print(xs)
print('')
print(
' -> ' + repr(nthForwardDifference(xs)(9))
)
print('\nSuccessive orders of forward difference:')
print(unlines([
str(i) + ' -> ' + repr(x) for i, x in
enumerate(take(10)(
iterate(forwardDifference)(xs)
))
]))
# ------------------- GENERIC FUNCTIONS -------------------
# index (!!) :: [a] -> Int -> a
def index(xs):
'''Item at given (zero-based) index.'''
return lambda n: None if 0 > n else (
xs[n] if (
hasattr(xs, "__getitem__")
) else next(islice(xs, n, None))
)
# iterate :: (a -> a) -> a -> Gen [a]
def iterate(f):
'''An infinite list of repeated
applications of f to x.
'''
def go(x):
v = x
while True:
yield v
v = f(v)
return go
# 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, tuple))
else list(islice(xs, n))
)
# unlines :: [String] -> String
def unlines(xs):
'''A single string formed by the intercalation
of a list of strings with the newline character.
'''
return '\n'.join(xs)
# MAIN ---
if __name__ == '__main__':
main()