162 lines
4.2 KiB
JavaScript
162 lines
4.2 KiB
JavaScript
(() => {
|
|
"use strict";
|
|
|
|
// ----- MINIMUM LENGTH OF UNIQUE ABBREVIATIONS ------
|
|
|
|
// minAbbrevnLength :: [String] -> Int
|
|
const minAbbrevnLength = xs => {
|
|
const n = xs.length;
|
|
|
|
return 0 < n ? (() => {
|
|
const
|
|
abbrs = dropWhile(ks => n > ks.length)(
|
|
transpose(xs.map(inits))
|
|
.map(prefixes => Array.from(
|
|
new Set(
|
|
prefixes.map(ws => ws.join(""))
|
|
)
|
|
))
|
|
);
|
|
|
|
return (abbrs.length && abbrs[0][0].length) || (
|
|
maximum(xs.map(x => x.length))
|
|
);
|
|
})() : 0;
|
|
};
|
|
|
|
// ---------------------- TEST -----------------------
|
|
// main :: IO ()
|
|
const main = () =>
|
|
readFile(
|
|
"~/Desktop/weekDayNames.txt"
|
|
)
|
|
.split("\n")
|
|
// Display of just the first few lines.
|
|
.slice(0, 10)
|
|
.map(s => {
|
|
const
|
|
ws = words(s),
|
|
n = minAbbrevnLength(ws);
|
|
|
|
return `${n}: ${ws.map(w => w.slice(0, n))}`;
|
|
})
|
|
.join("\n");
|
|
|
|
|
|
// ----------- MACOS JS FOR AUTOMATION IO ------------
|
|
|
|
// readFile :: FilePath -> IO String
|
|
const readFile = fp => {
|
|
// The contents of a text file at the
|
|
// filepath fp.
|
|
const
|
|
e = $(),
|
|
ns = $.NSString
|
|
.stringWithContentsOfFileEncodingError(
|
|
$(fp).stringByStandardizingPath,
|
|
$.NSUTF8StringEncoding,
|
|
e
|
|
);
|
|
|
|
return ObjC.unwrap(
|
|
ns.isNil() ? (
|
|
e.localizedDescription
|
|
) : ns
|
|
);
|
|
};
|
|
|
|
// --------------------- GENERIC ---------------------
|
|
|
|
// dropWhile :: (a -> Bool) -> [a] -> [a]
|
|
// dropWhile :: (Char -> Bool) -> String -> String
|
|
const dropWhile = p =>
|
|
// The suffix remainining after takeWhile p xs.
|
|
xs => {
|
|
const n = xs.length;
|
|
|
|
return xs.slice(
|
|
0 < n ? until(
|
|
i => n === i || !p(xs[i])
|
|
)(i => 1 + i)(0) : 0
|
|
);
|
|
};
|
|
|
|
|
|
// inits :: [a] -> [[a]]
|
|
// inits :: String -> [String]
|
|
const inits = xs =>
|
|
// All prefixes of the argument,
|
|
// shortest first.
|
|
[...xs].map(
|
|
(_, i, ys) => ys.slice(0, 1 + i)
|
|
);
|
|
|
|
|
|
// maximum :: Ord a => [a] -> a
|
|
const maximum = xs => (
|
|
// The largest value in a non-empty list.
|
|
ys => 0 < ys.length ? (
|
|
ys.slice(1).reduce(
|
|
(a, y) => y > a ? (
|
|
y
|
|
) : a, ys[0]
|
|
)
|
|
) : undefined
|
|
)(xs);
|
|
|
|
|
|
// transpose :: [[a]] -> [[a]]
|
|
const transpose = rows => {
|
|
// If any rows are shorter than those that follow,
|
|
// their elements are skipped:
|
|
// > transpose [[10,11],[20],[],[30,31,32]]
|
|
// == [[10,20,30],[11,31],[32]]
|
|
const go = xss =>
|
|
0 < xss.length ? (() => {
|
|
const
|
|
h = xss[0],
|
|
t = xss.slice(1);
|
|
|
|
return 0 < h.length ? [
|
|
[h[0]].concat(t.reduce(
|
|
(a, xs) => a.concat(
|
|
0 < xs.length ? (
|
|
[xs[0]]
|
|
) : []
|
|
),
|
|
[]
|
|
))
|
|
].concat(go([h.slice(1)].concat(
|
|
t.map(xs => xs.slice(1))
|
|
))) : go(t);
|
|
})() : [];
|
|
|
|
return go(rows);
|
|
};
|
|
|
|
|
|
// until :: (a -> Bool) -> (a -> a) -> a -> a
|
|
const until = p =>
|
|
// The value resulting from repeated applications
|
|
// of f to the seed value x, terminating when
|
|
// that result returns true for the predicate p.
|
|
f => x => {
|
|
let v = x;
|
|
|
|
while (!p(v)) {
|
|
v = f(v);
|
|
}
|
|
|
|
return v;
|
|
};
|
|
|
|
|
|
// words :: String -> [String]
|
|
const words = s =>
|
|
// List of space-delimited sub-strings.
|
|
s.split(/\s+/u);
|
|
|
|
// MAIN ---
|
|
return main();
|
|
})();
|