union-find-ts
Version:
An immutable Union-Find structure.
37 lines (36 loc) • 1.75 kB
JavaScript
import { Just, Nothing } from 'purify-ts';
import { any, concat, prepend } from 'ramda';
import { find, findItem, hasGroup, linkItemAll } from './UnionFind';
export const findPath = (uf, candidates, src, dest) => {
const destGroup = findItem(uf, dest);
const newUF = {
...uf,
ranks: uf.ranks.map((it, idx) => (find(uf, idx) === destGroup ? it : 0)),
roots: uf.roots.map(it => (find(uf, it) === destGroup ? it : 0))
};
return _findPath(uf, newUF, candidates, src, dest, []);
};
const joinSolutions = (left, right) => {
const comp = left[0].length - right[0].length;
return comp === 0 ? concat(left, right) : comp < 0 ? left : right;
};
function _findPath(ufInitial, uf, candidates, item, group2, seen) {
const srcComponent = findItem(uf, item);
const adjacent = candidates(item, uf).filter(it => findItem(uf, it) !== srcComponent);
const destGroup = findItem(uf, group2);
if (any(it => findItem(uf, it) === destGroup, adjacent)) {
return Just([[]]);
}
// The trick is that in order to make links, I need to
// also link to anything else on the
return adjacent.reduce(({ uf: accUf, solutions, seen: innerSeen }, candidate) => {
innerSeen = prepend(candidate, innerSeen);
return {
seen: innerSeen,
uf: accUf,
solutions: _findPath(ufInitial, accUf, candidates, candidate, group2, innerSeen)
.map(it => hasGroup(ufInitial, candidate) ? it : it.map(path => prepend(candidate, path)))
.reduce((previous, currentValue) => Just(previous.reduce(joinSolutions, currentValue)), solutions)
};
}, { uf: linkItemAll(uf, item, adjacent), solutions: Nothing, seen }).solutions;
}