RosettaCodeData/Task/Sparkline-in-unicode/Python/sparkline-in-unicode-2.py

114 lines
2.4 KiB
Python

import re
# sparkLine :: [Float] -> [String]
def sparkLine(xs):
def go(xs):
ys = sorted(xs)
mn, mx = ys[0], ys[-1]
n = len(xs)
mid = n // 2
w = (mx - mn) / 8
lbounds = list(map(lambda i: mn + (w * i), range(1, 8)))
return [
''.join(map(
lambda x: maybe('')(
lambda i: '▁▂▃▄▅▆▇'[i]
)(findIndex(lambda b: b > x)(lbounds)),
xs
)),
' '.join(map(str, xs)),
'\t'.join([
'Min ' + str(mn),
'Mean ' + str(round(mean(xs), 2)),
'Median ' + str(
(ys[mid - 1] + ys[mid]) / 2 if even(n) else (
ys[mid]
)
),
'Max ' + str(mx)
]),
''
]
return go(xs) if xs else []
# main :: IO ()
def main():
print(
unlines(map(
compose(compose(unlines)(sparkLine))(readFloats),
[
"0, 1, 19, 20",
"0, 999, 4000, 4999, 7000, 7999",
"1 2 3 4 5 6 7 8 7 6 5 4 3 2 1",
"1.5, 0.5 3.5, 2.5 5.5, 4.5 7.5, 6.5"
]
))
)
# GENERIC -------------------------------------------------
# Just :: a -> Maybe a
def Just(x):
return {'type': 'Maybe', 'Nothing': False, 'Just': x}
# Nothing :: Maybe a
def Nothing():
return {'type': 'Maybe', 'Nothing': True}
# compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
def compose(g):
return lambda f: lambda x: g(f(x))
# even :: Int -> Bool
def even(x):
return 0 == x % 2
# findIndex :: (a -> Bool) -> [a] -> Maybe Int
def findIndex(p):
def go(xs):
try:
return Just(next(
i for i, v in enumerate(xs) if p(v)
))
except StopIteration:
return Nothing()
return lambda xs: go(xs)
# maybe :: b -> (a -> b) -> Maybe a -> b
def maybe(v):
return lambda f: lambda m: v if m.get('Nothing') else (
f(m.get('Just'))
)
# mean :: [Num] -> Float
def mean(xs):
return sum(xs) / float(len(xs))
# readFloats :: String -> [Float]
def readFloats(s):
return list(map(
float,
re.split('[\s,]+', s)
))
# unlines :: [String] -> String
def unlines(xs):
return '\n'.join(xs)
# TEST -------------------------------------------------
if __name__ == '__main__':
main()