67 lines
1.7 KiB
JavaScript
67 lines
1.7 KiB
JavaScript
(() => {
|
|
'use strict';
|
|
|
|
// ---------------- RANGE EXTRACTION -----------------
|
|
|
|
// rangeFormat :: [Int] -> String
|
|
const rangeFormat = xs =>
|
|
splitBy((a, b) => b - a > 1, xs)
|
|
.map(rangeString)
|
|
.join(',');
|
|
|
|
// rangeString :: [Int] -> String
|
|
const rangeString = xs =>
|
|
xs.length > 2 ? (
|
|
[xs[0], last(xs)].map(show)
|
|
.join('-')
|
|
) : xs.join(',')
|
|
|
|
|
|
// ---------------------- TEST -----------------------
|
|
const main = () =>
|
|
rangeFormat([0, 1, 2, 4, 6, 7, 8, 11, 12, 14,
|
|
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
|
25, 27, 28, 29, 30, 31, 32, 33, 35, 36,
|
|
37, 38, 39
|
|
]);
|
|
|
|
|
|
// ---------------- GENERIC FUNCTIONS ----------------
|
|
|
|
// Splitting not on a delimiter, but whenever the
|
|
// relationship between two consecutive items matches
|
|
// a supplied predicate function
|
|
|
|
// splitBy :: (a -> a -> Bool) -> [a] -> [[a]]
|
|
const splitBy = (f, xs) => {
|
|
if (xs.length < 2) return [xs];
|
|
const
|
|
h = xs[0],
|
|
lstParts = xs.slice(1)
|
|
.reduce(([acc, active, prev], x) =>
|
|
f(prev, x) ? (
|
|
[acc.concat([active]), [x], x]
|
|
) : [acc, active.concat(x), x], [
|
|
[],
|
|
[h],
|
|
h
|
|
]);
|
|
return lstParts[0].concat([lstParts[1]]);
|
|
};
|
|
|
|
// last :: [a] -> a
|
|
const last = xs => (
|
|
// The last item of a list.
|
|
ys => 0 < ys.length ? (
|
|
ys.slice(-1)[0]
|
|
) : undefined
|
|
)(xs);
|
|
|
|
// show :: a -> String
|
|
const show = x =>
|
|
JSON.stringify(x);
|
|
|
|
// MAIN --
|
|
return main();
|
|
})();
|