65 lines
1.8 KiB
JavaScript
65 lines
1.8 KiB
JavaScript
(() => {
|
|
'use strict';
|
|
|
|
const symmetricDifference = (xs, ys) =>
|
|
union(difference(xs, ys), difference(ys, xs));
|
|
|
|
|
|
// GENERIC FUNCTIONS ------------------------------------------------------
|
|
|
|
// First instance of x (if any) removed from xs
|
|
// delete_ :: Eq a => a -> [a] -> [a]
|
|
const delete_ = (x, xs) => {
|
|
const i = xs.indexOf(x);
|
|
return i !== -1 ? (xs.slice(0, i)
|
|
.concat(xs.slice(i, -1))) : xs;
|
|
};
|
|
|
|
// (\\) :: (Eq a) => [a] -> [a] -> [a]
|
|
const difference = (xs, ys) =>
|
|
ys.reduce((a, x) => filter(z => z !== x, a), xs);
|
|
|
|
// filter :: (a -> Bool) -> [a] -> [a]
|
|
const filter = (f, xs) => xs.filter(f);
|
|
|
|
// flip :: (a -> b -> c) -> b -> a -> c
|
|
const flip = f => (a, b) => f.apply(null, [b, a]);
|
|
|
|
// foldl :: (b -> a -> b) -> b -> [a] -> b
|
|
const foldl = (f, a, xs) => xs.reduce(f, a);
|
|
|
|
// nub :: [a] -> [a]
|
|
const nub = xs => {
|
|
const mht = unconsMay(xs);
|
|
return mht.nothing ? xs : (
|
|
([h, t]) => [h].concat(nub(t.filter(s => s !== h)))
|
|
)(mht.just);
|
|
};
|
|
|
|
// show :: a -> String
|
|
const show = x => JSON.stringify(x, null, 2);
|
|
|
|
// unconsMay :: [a] -> Maybe (a, [a])
|
|
const unconsMay = xs => xs.length > 0 ? {
|
|
just: [xs[0], xs.slice(1)],
|
|
nothing: false
|
|
} : {
|
|
nothing: true
|
|
};
|
|
|
|
// union :: [a] -> [a] -> [a]
|
|
const union = (xs, ys) => {
|
|
const sx = nub(xs);
|
|
return sx.concat(foldl(flip(delete_), nub(ys), sx));
|
|
};
|
|
|
|
// TEST -------------------------------------------------------------------
|
|
const
|
|
a = ["John", "Serena", "Bob", "Mary", "Serena"],
|
|
b = ["Jim", "Mary", "John", "Jim", "Bob"];
|
|
|
|
return show(
|
|
symmetricDifference(a, b)
|
|
);
|
|
})();
|