import type { Fn , Fn0 , IObjectOf } from "@thi.ng/api" ; import type { Reducer } from "./api.js" ; import { groupByObj } from "./group-by-obj.js" ; import { push } from "./push.js" ; const branchPred = < T > ( key , b , l , r ) => ( x ) => key ( x ) & b ? r : l ; /**
 * Creates a bottom-up, unbalanced binary tree of desired depth and
 * choice of data structures. Any value can be indexed, as long as a
 * numeric representation (key) can be obtained. This numeric key is
 * produced by the supplied `key` function. IMPORTANT: the returned
 * values MUST be unsigned and less than the provided bit length (i.e.
 * `0 .. (2^bits) - 1` range).
 *
 * By default the tree is constructed using plain objects for branches,
 * with left branches stored as "l" and right ones as "r". The original
 * values are stored at the lowest tree level using a customizable
 * nested reducer. By default leaves are collected in arrays (using the
 *  {@link (push:1)} reducer), but any suitable reducer can be used (e.g.
 *  {@link (conj:1)} to collect values into sets).
 *
 * Index by lowest 4-bits of ID value:
 *
 *  example example ```ts
 * tree = reduce(
 *   groupBinary(4, identity, ()=>[], push(), 0, 1),
 *   [1,2,3,4,5,6,7]
 * )
 *
 * tree[0][1][0][1] // 0101 == 5 in binary
 * // [ 5 ]
 *
 * tree[0][1][1]    // 011* == branch
 * // [ [ 6 ], [ 7 ] ]
 * ```
 *
 * Using  {@link (frequencies:1)} as leaf reducer:
 *
 *  example param bits param key param branch param leaf param left param right export const groupBinary = < T > ( bits , key , branch ? , leaf ? , left = "l" , right = "r" ) : Reducer < any , T > => { const init = branch || ( ( ) => ( { } ) ) ; let rfn = groupByObj ( { key : branchPred ( key , 1 , left , right ) , group : leaf || push ( ) , } ) ; for ( let i = 2 , maxIndex = 1 << bits ; i < maxIndex ; i <<= 1 ) { rfn = groupByObj ( { key : branchPred ( key , i , left , right ) , group : [ init , rfn [ 1 ] , rfn [ 2 ] ] , } ) ; } return [ init , rfn [ 1 ] , rfn [ 2 ] ] ; } ;