RosettaCodeData/Task/Set-consolidation/JavaScript/set-consolidation.js

122 lines
3.4 KiB
JavaScript

(() => {
'use strict';
// consolidated :: Ord a => [Set a] -> [Set a]
const consolidated = xs => {
const go = (s, xs) =>
0 !== xs.length ? (() => {
const h = xs[0];
return 0 === intersection(h, s).size ? (
[h].concat(go(s, tail(xs)))
) : go(union(h, s), tail(xs));
})() : [s];
return foldr(go, [], xs);
};
// TESTS ----------------------------------------------
const main = () =>
map(xs => intercalate(
', and ',
map(showSet, consolidated(xs))
),
map(x => map(
s => new Set(chars(s)),
x
),
[
['ab', 'cd'],
['ab', 'bd'],
['ab', 'cd', 'db'],
['hik', 'ab', 'cd', 'db', 'fgh']
]
)
).join('\n');
// GENERIC FUNCTIONS ----------------------------------
// chars :: String -> [Char]
const chars = s => s.split('');
// concat :: [[a]] -> [a]
// concat :: [String] -> String
const concat = xs =>
0 < xs.length ? (() => {
const unit = 'string' !== typeof xs[0] ? (
[]
) : '';
return unit.concat.apply(unit, xs);
})() : [];
// elems :: Dict -> [a]
// elems :: Set -> [a]
const elems = x =>
'Set' !== x.constructor.name ? (
Object.values(x)
) : Array.from(x.values());
// flip :: (a -> b -> c) -> b -> a -> c
const flip = f =>
1 < f.length ? (
(a, b) => f(b, a)
) : (x => y => f(y)(x));
// Note that that the Haskell signature of foldr differs 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);
// intercalate :: [a] -> [[a]] -> [a]
// intercalate :: String -> [String] -> String
const intercalate = (sep, xs) =>
0 < xs.length && 'string' === typeof sep &&
'string' === typeof xs[0] ? (
xs.join(sep)
) : concat(intersperse(sep, xs));
// intersection :: Ord a => Set a -> Set a -> Set a
const intersection = (s, s1) =>
new Set([...s].filter(x => s1.has(x)));
// intersperse :: a -> [a] -> [a]
// intersperse :: Char -> String -> String
const intersperse = (sep, xs) => {
const bln = 'string' === typeof xs;
return xs.length > 1 ? (
(bln ? concat : x => x)(
(bln ? (
xs.split('')
) : xs)
.slice(1)
.reduce((a, x) => a.concat([sep, x]), [xs[0]])
)) : xs;
};
// map :: (a -> b) -> [a] -> [b]
const map = (f, xs) => xs.map(f);
// showSet :: Set -> String
const showSet = s =>
intercalate(elems(s), ['{', '}']);
// sort :: Ord a => [a] -> [a]
const sort = xs => xs.slice()
.sort((a, b) => a < b ? -1 : (a > b ? 1 : 0));
// tail :: [a] -> [a]
const tail = xs => 0 < xs.length ? xs.slice(1) : [];
// union :: Ord a => Set a -> Set a -> Set a
const union = (s, s1) =>
Array.from(s1.values())
.reduce(
(a, x) => (a.add(x), a),
new Set(s)
);
// MAIN ---
return main();
})();