// License: LGPL-3.0-or-later // from https://github.com/mtraynham/lodash-joins/blob/c252b462981562451d85d1e09c8f273ce7fe06c5/lib/hash/hashFullOuterJoin.ts import filter from 'lodash/filter'; import flatten from 'lodash/flatten'; import groupBy from 'lodash/groupBy'; import has from 'lodash/has'; import map from 'lodash/map'; import reduceRight from 'lodash/reduceRight'; import values from 'lodash/values'; import {Accessor, Merger} from '../typings'; import {toStringAccessor} from './util'; /** * Hash full outer join */ export default function hashFullOuterJoin( a: LeftRow[], aAccessor: Accessor, b: RightRow[], bAccessor: Accessor, merger: Merger ): MergeResult[] { if (a.length < 1 || b.length < 1) { return [ ...a.map((a: LeftRow) => merger(a, undefined)), ...b.map((b: RightRow) => merger(undefined, b)) ]; } const leftAccessor: Accessor = toStringAccessor(aAccessor), rightAccessor: Accessor = toStringAccessor(bAccessor), seen: {[key: string]: boolean} = {}; let index: {[key: string]: (LeftRow | RightRow)[]}, result: MergeResult[], key: string; if (a.length < b.length) { index = groupBy(a, leftAccessor); result = reduceRight(b, (previous: MergeResult[], bDatum: RightRow) => { seen[key = rightAccessor(bDatum)] = true; if (has(index, key)) { return map(index[key], (aDatum: LeftRow) => merger(aDatum, bDatum)).concat(previous); } previous.unshift(merger(undefined, bDatum)); return previous; }, []); return result.concat( map( flatten(values(filter( index, (val: (LeftRow | RightRow)[], key: string) => !has(seen, key)))), (aDatum: LeftRow) => merger(aDatum, undefined))); } index = groupBy(b, rightAccessor); result = reduceRight(a, (previous: MergeResult[], aDatum: LeftRow) => { seen[key = leftAccessor(aDatum)] = true; if (has(index, key)) { return map(index[key], (bDatum: RightRow) => merger(aDatum, bDatum)).concat(previous); } previous.unshift(merger(aDatum, undefined)); return previous; }, []); return result.concat( map( flatten(values(filter( index, (val: (LeftRow | RightRow)[], key: string) => !has(seen, key)))), (bDatum: RightRow) => merger(undefined, bDatum))); }