upsetjs import type { ISetLike } from '../model' ; export interface ISetOverlapFunction < T > { ( a , b ) : number ; } export interface SetOverlap { setA : number ; setB : number ; union : number ; intersection : number ; } export interface SetElemOverlap < T > { setA : readonly T [ ] ; setB : readonly T [ ] ; union : readonly T [ ] ; intersection : readonly T [ ] ; } function len < T > ( a ) { return a instanceof Set ? a . size : a . length ; } export function setOverlapFactory < T > ( a , toElemKey ? ) { const elems = ! toElemKey ? a instanceof Set ? a : new Set ( a ) : new Set ( ( a instanceof Set ? Array . from ( a ) : a ) . map ( toElemKey ) ) ; const setA = elems . size ; const same = { setA , setB : setA , union : setA , intersection : setA , } ; return ( b ) : SetOverlap => { if ( b === a ) { return same ; } let intersection = 0 ; b . forEach ( ( e ) => { if ( ( toElemKey && ( elems as Set < string > ) . has ( toElemKey ( e ) ) ) || ( ! toElemKey && ( elems as Set < T > ) . has ( e ) ) ) { intersection ++ ; } } ) ; const setB = len ( b ) ; return { setA , setB , intersection , union : setA + setB - intersection , } ; } ; } export default function setOverlap < T > ( a , b , toElemKey ? ) { if ( len ( a ) < len ( b ) || a instanceof Set ) { return setOverlapFactory ( a , toElemKey ) ( b ) ; } const r = setOverlapFactory ( b , toElemKey ) ( a ) ; return Object . assign ( { } , r , { setA : r . setB , setB : r . setA , } ) ; } export function setElemOverlapFactory < T > ( a , toElemKey ? ) { const elems = ! toElemKey ? a instanceof Set ? a : new Set ( a ) : new Set ( ( a instanceof Set ? Array . from ( a ) : a ) . map ( toElemKey ) ) ; const setA = Array . isArray ( a ) ? a : Array . from ( a ) ; const same = { setA , setB : setA , union : setA , intersection : setA , } ; return ( b ) : SetElemOverlap < T > => { if ( b === a ) { return same ; } const intersection = [ ] ; const union = setA . slice ( ) ; b . forEach ( ( e ) => { if ( ( toElemKey && ( elems as Set < string > ) . has ( toElemKey ( e ) ) ) || ( ! toElemKey && ( elems as Set < T > ) . has ( e ) ) ) { intersection . push ( e ) ; } else { union . push ( e ) ; } } ) ; return { setA : setA , setB : Array . isArray ( b ) ? b : Array . from ( b ) , intersection , union , } ; } ; } export function setElemOverlap < T > ( a , b , toElemKey ? ) { if ( len ( a ) < len ( b ) || a instanceof Set ) { return setElemOverlapFactory ( a , toElemKey ) ( b ) ; } const r = setElemOverlapFactory ( b , toElemKey ) ( a ) ; return Object . assign ( { } , r , { setA : r . setB , setB : r . setA , } ) ; } export function setElemIntersectionFactory < T > ( a , toElemKey ? ) { const arr = a instanceof Set ? Array . from ( a ) : a ; const elems = ! toElemKey ? ( a instanceof Set ? a : new Set ( a ) ) : new Set ( arr . map ( toElemKey ) ) ; return ( b ) : readonly T [ ] => { if ( b === a ) { return arr ; } const intersection = [ ] ; b . forEach ( ( e ) => { if ( ( toElemKey && ( elems as Set < string > ) . has ( toElemKey ( e ) ) ) || ( ! toElemKey && ( elems as Set < T > ) . has ( e ) ) ) { intersection . push ( e ) ; } } ) ; return intersection ; } ; }