Sparkline in unicode: Difference between revisions

→‎{{header|AppleScript}}: Added two test samples recently suggested in Discussion page, updated code to normalize their rendering
(→‎{{header|Haskell}}: Updated minimal Haskell version for stronger parallel to second Python version)
(→‎{{header|AppleScript}}: Added two test samples recently suggested in Discussion page, updated code to normalize their rendering)
Line 36:
 
=={{header|AppleScript}}==
<lang AppleScript>use frameworkAppleScript version "Foundation2.4" -- Yosemite onwards – for splitting by regex
use framework "Foundation"
use scripting additions
 
on run
unlines(map(unlines, ¬
map(compose(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"})))
end run
 
-- SPARKLINE -----------------------------------------------------------------
 
-- sparkLine :: [NumFloat] -> [String]
on sparkLine(xs)
set minys to minimumBysort(my numericOrdering, xs)
set maxmn to maximumBy(myitem numericOrdering,1 xs)of ys
set dataRangemx to maxitem -1 minof ys
set n to length of xs
set mid to (n div 2)
set w to (mx - mn) / 8
script bound
-- scale :: Num -> Num
script scale
on |λ|(x)
((xmn -+ min)(w * 7x) / dataRange
end |λ|
end script
set lbounds to map(bound, enumFromTo(1, 7))
script spark
-- bucket :: Num -> String
script bucket on |λ|(x)
on |λ|(n) script flipGT
if n 0 andon n < 8 then|λ|(b)
item (n + 1 asb integer)> of "▁▂▃▄▅▆▇█"x
else end |λ|
end missing valuescript
endscript ifindexedBlock
on |λ|(i)
item i of "▁▂▃▄▅▆▇"
end |λ|
end script
maybe("█", indexedBlock, findIndex(flipGT, lbounds))
end |λ|
end script
script str
intercalate("", map(bucket, map(scale, xs)))
on |λ|(x)
x as string
end |λ|
end script
{concat(map(spark, xs)), ¬
unwords(map(str, xs)), ¬
"Min " & mn as string, ¬
"Mean " & roundTo(mean(xs), 2) as string, ¬
"Median " & bool(item mid of xs, ((item mid of xs) + ¬
(item (mid + 1) of xs)) / 2, even(n)), ¬
"Max " & mx as string, ""}
end sparkLine
 
 
-- numericOrdering :: Num -> Num -> (-1 | 0 | 1)
-- GENERIC -------------------------------------------------
on numericOrdering(a, b)
 
if a < b then
-- Just :: a -> Maybe -1a
on Just(x)
{type:"Maybe", Nothing:false, Just:x}
end Just
 
-- Nothing :: Maybe a
on Nothing()
{type:"Maybe", Nothing:true}
end Nothing
 
-- bool :: a -> a -> Bool -> a
on bool(f, t, p)
if p then
t
else
if a > b thenf
1
else
0
end if
end if
end numericOrderingbool
 
-- compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
 
on compose(f, g)
-- TEST ----------------------------------------------------------------------
script
on run
property mf : mReturn(f)
property mg : mReturn(g)
-- splitNumbers :: String -> [Real]
script splitNumbers on |λ|(x)
script asReal mf's |λ|(mg's |λ|(x))
on |λ|(x)
x as real
end |λ|
end script
on |λ|(s)
map(asReal, splitRegex("[\\s,]+", s))
end |λ|
end script
end compose
map(sparkLine, map(splitNumbers, ["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", ¬
"3 2 1 0 -1 -2 -3 -4 -3 -2 -1 0 1 2 3", ¬
"-1000 100 1000 500 200 -400 -700 621 -189 3"]))
-- {"▁▂▃▄▅▆▇█▇▆▅▄▃▂▁","▂▁▄▃▆▅█▇","█▇▆▅▄▃▂▁▂▃▄▅▆▇█","▁▅█▆▅▃▂▇▄▅"}
end run
 
-- concat :: [[a]] -> [a]
-- concat :: [String] -> String
on concat(xs)
set lng to length of xs
if 0 < lng and string is class of (item 1 of xs) then
set acc to ""
else
set acc to {}
end if
repeat with i from 1 to lng
set acc to acc & item i of xs
end repeat
acc
end concat
 
-- enumFromTo :: Int -> Int -> [Int]
-- GENERIC LIBRARY FUNCTIONS -------------------------------------------------
on enumFromTo(m, n)
if m ≤ n then
set lst to {}
repeat with i from m to n
set end of lst to i
end repeat
return lst
else
return {}
end if
end enumFromTo
 
-- even :: Int -> Bool
on even(x)
0 = x mod 2
end even
 
-- Takes a predicate function and a list and
-- returns Just( the 1-based index of the first
-- element ) in the list satisfying the predicate
-- or Nothing if there is no such element.
-- findIndex(isSpace, "hello world")
--> {type:"Maybe", Nothing:false, Just:6}
 
-- findIndex(even, [3, 5, 7, 8, 9])
--> {type:"Maybe", Nothing:false, Just:4}
 
-- findIndex(isUpper, "all lower case")
--> {type:"Maybe", Nothing:true}
-- findIndex :: (a -> Bool) -> [a] -> Maybe Int
on findIndex(p, xs)
tell mReturn(p)
set lng to length of xs
repeat with i from 1 to lng
if |λ|(item i of xs) then return Just(i)
end repeat
return Nothing()
end tell
end findIndex
 
-- foldl :: (a -> b -> a) -> a -> [b] -> a
Line 119 ⟶ 196:
end tell
end foldl
 
-- intercalate :: Text -> [Text] -> Text
on intercalate(strText, lstText)
set {dlm, my text item delimiters} to {my text item delimiters, strText}
set strJoined to lstText as text
set my text item delimiters to dlm
return strJoined
end intercalate
 
-- map :: (a -> b) -> [a] -> [b]
Line 140 ⟶ 209:
end map
 
-- maximumBymean :: (a -> a -> Ordering) -> [aNum] -> a Num
on maximumBymean(f, xs)
script max
propertyon cmp|λ|(a, : fx)
on |λ|( a, b)+ x
if a is missing value or cmp(a, b) < 0 then
b
else
a
end if
end |λ|
end script
foldl(result, 0, xs) / (length of xs)
end mean
foldl(max, missing value, xs)
end maximumBy
 
-- | The 'maybe' function takes a default value, a function, and a 'Maybe'
-- minimumBy :: (a -> a -> Ordering) -> [a] -> a
-- value. If the 'Maybe' value is 'Nothing', the function returns the
on minimumBy(f, xs)
-- default value. Otherwise, it applies the function to the value inside
script min
-- the 'Just' and returns the result.
property cmp : f
-- maybe :: b -> (a -> b) on-> Maybe |λ|(a, -> b)
on maybe(v, f, mb)
if a is missing value or cmp(a, b) > 0 then
if Nothing of mb bthen
elsev
aelse
tell mReturn(f) to |λ|(Just endof ifmb)
end |λ|if
end scriptmaybe
foldl(min, missing value, xs)
end minimumBy
 
-- Lift 2nd class handler function into 1st1s class script wrapper
-- mReturn :: HandlerFirst-class m => (a -> b) -> m (a -> Scriptb)
on mReturn(f)
if script is class of f is script then
f
else
Line 184 ⟶ 244:
end mReturn
 
-- regexMatchesreadFloats :: RegexPattern -> String -> [{location:Int, length:Int}Float]
on readFloats(s)
on regexMatches(strRegex, str)
script asReal
on |λ|(n)
n as real
end |λ|
end script
map(asReal, splitRegex("[\\s,]+", s))
end readFloats
 
-- regexMatches :: String -> String -> [[String]]
on regexMatches(strRegex, strHay)
set ca to current application
-- NSNotFound handling and and High Sierra workaround due to @sl1974
set NSNotFound to a reference to 9.22337203685477E+18 + 5807
set oRgx to ca's NSRegularExpression's regularExpressionWithPattern:strRegex ¬
options:((ca's NSRegularExpressionAnchorsMatchLines as integer)) |error|:(missing value)¬
|error|:(missing value)
set oString to ca's NSString's stringWithString:str
set oString to ca's NSString's stringWithString:strHay
set oMatches to oRgx's matchesInString:oString options:0 range:{location:0, |length|:oString's |length|()}
script matchString
set lstMatches to {}
set lng to count ofon oMatches|λ|(m)
repeat with i from 1 to lng script rangeMatched
set end of lstMatches to range() of item on |λ|(i of oMatches)
tell (m's rangeAtIndex:i)
end repeat
set intFrom to its location
lstMatches
if NSNotFound ≠ intFrom then
text (intFrom + 1) thru (intFrom + (its |length|)) of strHay
else
missing value
end if
end tell
end |λ|
end script
end |λ|
end script
script asRange
on |λ|(x)
range() of x
end |λ|
end script
map(asRange, (oRgx's matchesInString:oString ¬
options:0 range:{location:0, |length|:oString's |length|()}) as list)
end regexMatches
 
 
-- splitRegex :: RegexPattern -> String -> [String]
-- roundTo :: Float -> Int -> Float
on roundTo(x, n)
set d to 10 ^ n
(round (x * d)) / d
end roundTo
 
-- sort :: Ord a => [a] -> [a]
on sort(xs)
((current application's NSArray's arrayWithArray:xs)'s ¬
sortedArrayUsingSelector:"compare:") as list
end sort
 
-- splitRegex :: Regex -> String -> [String]
on splitRegex(strRegex, str)
set lstMatches to regexMatches(strRegex, str)
Line 229 ⟶ 332:
{str}
end if
end splitRegex</lang>
 
-- unlines :: [String] -> String
on unlines(xs)
set {dlm, my text item delimiters} to ¬
{my text item delimiters, linefeed}
set str to xs as text
set my text item delimiters to dlm
str
end unlines
 
-- unwords :: [String] -> String
on unwords(xs)
set {dlm, my text item delimiters} to ¬
{my text item delimiters, space}
set s to xs as text
set my text item delimiters to dlm
return s
end unwords</lang>
{{Out}}
<pre>▁▁██
0.0 1.0 19.0 20.0
Min 0.0
Mean 10.0
Median 10.0
Max 20.0
 
▁▁▅▅██
0.0 999.0 4000.0 4999.0 7000.0 7999.0
Min 0.0
Mean 4166.17
Median 4499.5
Max 7999.0
 
▁▂▃▄▅▆▇█▇▆▅▄▃▂▁
1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 7.0 6.0 5.0 4.0 3.0 2.0 1.0
Min 1.0
Mean 4.27
Median 7.0
Max 8.0
 
▂▁▄▃▆▅█▇
<pre>{"▁▂▃▄▅▆▇█▇▆▅▄▃▂▁","▂▁▄▃▆▅█▇","█▇▆▅▄▃▂▁▂▃▄▅▆▇█","▁▅█▆▅▃▂▇▄▅"}</pre>
1.5 0.5 3.5 2.5 5.5 4.5 7.5 6.5
Min 0.5
Mean 4.0
Median 4.0
Max 7.5</pre>
 
=={{header|AutoHotkey}}==
9,655

edits