June 2018 Update

This commit is contained in:
Ingy döt Net 2018-06-22 20:57:24 +00:00
parent ba8067c3b7
commit 22f33d4004
5278 changed files with 84726 additions and 14379 deletions

View file

@ -1,6 +1,6 @@
Create a well-formatted [[wp:Stem-and-leaf_plot|stem-and-leaf plot]] from the following data set, where the leaves are the last digits:
<blockquote style="font-family: monospace; white-space: pre-wrap;"><small>12 127 28 42 39 113 42 18 44 118 44 37 113 124 37 48 127 36 29 31 125 139 131 115 105 132 104 123 35 113 122 42 117 119 58 109 23 105 63 27 44 105 99 41 128 121 116 125 32 61 37 127 29 113 121 58 114 126 53 114 96 25 109 7 31 141 46 13 27 43 117 116 27 7 68 40 31 115 124 42 128 52 71 118 117 38 27 106 33 117 116 111 40 119 47 105 57 122 109 124 115 43 120 43 27 27 18 28 48 125 107 114 34 133 45 120 30 127 31 116 146</small></blockquote>
<blockquote style="font-family: monospace; white-space: pre-wrap;">12 127 28 42 39 113 42 18 44 118 44 37 113 124 37 48 127 36 29 31 125 139 131 115 105 132 104 123 35 113 122 42 117 119 58 109 23 105 63 27 44 105 99 41 128 121 116 125 32 61 37 127 29 113 121 58 114 126 53 114 96 25 109 7 31 141 46 13 27 43 117 116 27 7 68 40 31 115 124 42 128 52 71 118 117 38 27 106 33 117 116 111 40 119 47 105 57 122 109 124 115 43 120 43 27 27 18 28 48 125 107 114 34 133 45 120 30 127 31 116 146</blockquote>
<!-- The data set generation parameters: humps at 0 and 80 of width 80, 60 elements, slopes 3 and 6. -->
The primary intent of this task is the presentation of information. It is acceptable to hardcode the data set or characteristics of it (such as what the stems are) in the example, insofar as it is impractical to make the example generic to any data set. For example, in a computation-less language like HTML the data set may be entirely prearranged within the example; the interesting characteristics are how the proper visual formatting is arranged.

View file

@ -0,0 +1,72 @@
import Data.List (groupBy, intersperse, mapAccumL, sortBy)
import Data.Ord (comparing)
import Data.Function (on)
import Control.Arrow ((&&&))
-- Strings derived from integers,
-- and split into [(initial string, final character)] tuples.
xs :: [(String, Char)]
xs = (init &&& last) . show <$> [
12, 127, 28, 42, 39, 113, 42, 18, 44, 118, 44, 37, 113, 124, 37, 48,
127, 36, 29, 31, 125, 139, 131, 115, 105, 132, 104, 123, 35, 113, 122,
42, 117, 119, 58, 109, 23, 105, 63, 27, 44, 105, 99, 41, 128, 121, 116,
125, 32, 61, 37, 127, 29, 113, 121, 58, 114, 126, 53, 114, 96, 25, 109,
7, 31, 141, 46, 13, 27, 43, 117, 116, 27, 7, 68, 40, 31, 115, 124, 42,
128, 52, 71, 118, 117, 38, 27, 106, 33, 117, 116, 111, 40, 119, 47, 105,
57, 122, 109, 124, 115, 43, 120, 43, 27, 27, 18, 28, 48, 125, 107,
114, 34, 133, 45, 120, 30, 127, 31, 116, 146
]
-- Re-reading the initial strings as Ints
-- (empty strings read as 0),
ns :: [(Int, Char)]
ns =
(\x ->
let s = fst x
in ( if null s
then 0
else (read s :: Int)
, snd x)) <$>
xs
-- and sorting and grouping by these initial Ints,
-- interpreting them as data-collection bins.
bins :: [[(Int, Char)]]
bins =
groupBy (on (==) fst) (sortBy (mappend (comparing fst) (comparing snd)) ns)
-- Forming bars by the ordered accumulation of final characters in each bin,
bars :: [(Int, String)]
bars = (fst . head &&& fmap snd) <$> bins
-- and obtaining a complete series, with empty bar strings
-- interpolated for any missing integers.
series :: [(Int, String)]
series =
(concat . snd) $
mapAccumL
(\a x ->
let n = fst x
in if a == n
then (a + 1, [x])
else (n + 1, ((\i -> (i, "")) <$> [a .. (n - 1)]) ++ [x]))
1
bars
-- Assembling the series as a list of strings with right-justified indices,
justifyRight :: Int -> Char -> String -> String
justifyRight n c s = drop (length s) (replicate n c ++ s)
plotLines :: [String]
plotLines =
foldr
(\x a ->
(justifyRight 2 ' ' (show (fst x)) ++ " | " ++ intersperse ' ' (snd x)) :
a)
[]
series
-- and passing these over to IO as a single newline-delimited string.
main :: IO ()
main = putStrLn $ unlines plotLines

View file

@ -0,0 +1,211 @@
(() => {
// main :: IO String
const main = () => {
// Strings derived from integers,
// and split into [(initial string, final character)] tuples.
// xs :: [(String, Char)]
const xs = map(n => fanArrow(init, last)(n.toString()), [
12, 127, 28, 42, 39, 113, 42, 18, 44, 118, 44, 37, 113, 124,
37, 48, 127, 36, 29, 31, 125, 139, 131, 115, 105, 132, 104,
123, 35, 113, 122, 42, 117, 119, 58, 109, 23, 105, 63, 27,
44, 105, 99, 41, 128, 121, 116, 125, 32, 61, 37, 127, 29, 113,
121, 58, 114, 126, 53, 114, 96, 25, 109, 7, 31, 141, 46, 13, 27,
43, 117, 116, 27, 7, 68, 40, 31, 115, 124, 42, 128, 52, 71, 118,
117, 38, 27, 106, 33, 117, 116, 111, 40, 119, 47, 105, 57, 122,
109, 124, 115, 43, 120, 43, 27, 27, 18, 28, 48, 125, 107, 114,
34, 133, 45, 120, 30, 127, 31, 116, 146
]);
// Re-reading the initial strings as Ints
// (empty strings read as 0),
// ns :: [(Int, Char)]
const ns = map(x => {
const s = fst(x);
return Tuple(s.length > 0 ? (
parseInt(s, 10)
) : 0, snd(x));
}, xs);
// and sorting and grouping by these initial Ints,
// interpreting them as data-collection bins.
// bins :: [[(Int, Char)]]
const bins =
groupBy(
(a, b) => a[0] === b[0],
sortBy(mappendComparing([
[fst, true],
[snd, true]
]), ns)
);
// Forming bars by the ordered accumulation of
// final characters in each bin,
// bars :: [(Int, String)]
const bars = map(
fanArrow(
x => fst(x[0]),
x => map(snd, x)
),
bins
);
// and obtaining a complete series, with empty bars
// interpolated for any missing integers.
// series :: [(Int, String)]
const series = concat(mapAccumL(
(a, x) => {
const n = x[0];
return a !== n ? (
Tuple(1 + n,
map(i => Tuple(i, []),
enumFromToInt(a, n - 1)
)
.concat([x])
)
) : Tuple(1 + a, [x]);
}, 7, bars
)[1]);
// Assembling the series as a list of strings with
// right-justified indices,
// plotLines :: [String]
const plotLines = foldr(
(x, a) => cons(concat([
justifyRight(2, ' ', x[0].toString()),
' | ',
unwords(x[1])
]), a), [],
series
);
// and passing these over to IO as a single
// newline-delimited string.
return unlines(plotLines);
};
// GENERIC FUNCTIONS -----------------------------------------------------
// Tuple (,) :: a -> b -> (a, b)
const Tuple = (a, b) => ({
type: 'Tuple',
'0': a,
'1': b
});
// compare :: a -> a -> Ordering
const compare = (a, b) => a < b ? -1 : (a > b ? 1 : 0);
// concat :: [[a]] -> [a]
// concat :: [String] -> String
const concat = xs =>
xs.length > 0 ? (() => {
const unit = typeof xs[0] === 'string' ? '' : [];
return unit.concat.apply(unit, xs);
})() : [];
// cons :: a -> [a] -> [a]
const cons = (x, xs) => [x, ...xs];
// enumFromToInt :: Int -> Int -> [Int]
const enumFromToInt = (m, n) =>
n >= m ? Array.from({
length: Math.floor(n - m) + 1
}, (_, i) => m + i) : [];
// Compose a function from a simple value to a tuple of
// the separate outputs of two different functions
// fanArrow (&&&) :: (a -> b) -> (a -> c) -> (a -> (b, c))
const fanArrow = (f, g) => x => Tuple(f(x), g(x));
// flip :: (a -> b -> c) -> b -> a -> c
const flip = f => (a, b) => f.apply(null, [b, a]);
// Note that that the Haskell signature of foldr is different from that of
// foldl - the positions of accumulator and current value are reversed
// foldr :: (a -> b -> b) -> b -> [a] -> b
const foldr = (f, a, xs) => xs.reduceRight(flip(f), a);
// fst :: (a, b) -> a
const fst = tpl => tpl.type !== 'Tuple' ? undefined : tpl[0];
// Typical usage: groupBy(on(eq, f), xs)
// groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
const groupBy = (f, xs) => {
const dct = xs.slice(1)
.reduce((a, x) => {
const h = a.active.length > 0 ? a.active[0] : undefined;
return h !== undefined && f(h, x) ? {
active: a.active.concat([x]),
sofar: a.sofar
} : {
active: [x],
sofar: a.sofar.concat([a.active])
};
}, {
active: xs.length > 0 ? [xs[0]] : [],
sofar: []
});
return dct.sofar.concat(dct.active.length > 0 ? [dct.active] : []);
};
// init :: [a] -> [a]
const init = xs => xs.length > 0 ? xs.slice(0, -1) : undefined;
// justifyRight :: Int -> Char -> String -> String
const justifyRight = (n, cFiller, strText) =>
n > strText.length ? (
(cFiller.repeat(n) + strText)
.slice(-n)
) : strText;
// last :: [a] -> a
const last = xs => xs.length ? xs.slice(-1)[0] : undefined;
// map :: (a -> b) -> [a] -> [b]
const map = (f, xs) => xs.map(f);
// mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
const mapAccumL = (f, acc, xs) =>
xs.reduce((a, x, i) => {
const pair = f(a[0], x, i);
return Tuple(pair[0], a[1].concat(pair[1]));
}, Tuple(acc, []));
// mappendComparing :: [((a -> b), Bool)] -> (a -> a -> Ordering)
const mappendComparing = fboolPairs =>
(x, y) => fboolPairs.reduce(
(ordr, fb) => {
const f = fb[0];
return ordr !== 0 ? (
ordr
) : fb[1] ? (
compare(f(x), f(y))
) : compare(f(y), f(x));
}, 0
);
// snd :: (a, b) -> b
const snd = tpl => tpl.type !== 'Tuple' ? undefined : tpl[1];
// sortBy :: (a -> a -> Ordering) -> [a] -> [a]
const sortBy = (f, xs) =>
xs.slice()
.sort(f);
// unlines :: [String] -> String
const unlines = xs => xs.join('\n');
// unwords :: [String] -> String
const unwords = xs => xs.join(' ');
// MAIN ------------------------------------------------------------------
return main();
})();

View file

@ -0,0 +1,34 @@
# Project : Stem-and-leaf plot
# Date : 2018/03/16
# Author : Gal Zsolt [~ CalmoSoft ~]
# Email : <calmosoft@gmail.com>
data = list(120)
data = [12, 127, 28, 42, 39, 113, 42, 18, 44, 118, 44, 37, 113, 124,
37, 48, 127, 36, 29, 31, 125, 139, 131, 115, 105, 132, 104, 123,
35, 113, 122, 42, 117, 119, 58, 109, 23, 105, 63, 27, 44, 105,
99, 41, 128, 121, 116, 125, 32, 61, 37, 127, 29, 113, 121, 58,
114, 126, 53, 114, 96, 25, 109, 7, 31, 141, 46, 13, 27, 43,
117, 116, 27, 7, 68, 40, 31, 115, 124, 42, 128, 52, 71, 118,
117, 38, 27, 106, 33, 117, 116, 111, 40, 119, 47, 105, 57, 122,
109, 124, 115, 43, 120, 43, 27, 27, 18, 28, 48, 125, 107, 114,
34, 133, 45, 120, 30, 127, 31, 116, 146]
leafplot(data, len(data))
func leafplot(x,n)
c = n
x = sort(x)
i = floor(x[1] / 10 ) - 1
for j = 1 to n
d = floor(x[j] / 10)
while d > i
i = i + 1
if j > 0
see nl
ok
see "" + i + " |"
end
see "" + (x[j] % 10) + " "
next
see nl