import { IterableActivity , Source , isSource } from "./activity" ; import { extent } from "../observers/extent" ; import { scalar } from "../observers/observer" ; export type HistogramFn < T > = ( row : T ) => number ; export type HistogramRow < T > = { from : number ; to : number ; value : T [ ] ; } ; export type OptionA = { buckets : number ; } ; export type OptionB = { min : number ; range : number ; } ; export type Options = OptionA | OptionB ; function isOptionA ( _ ) { return ( _ as OptionA ) . buckets !== undefined ; } function histogramGen < T = any > ( callbackFn , options ) { return function * ( _source ) { let min ; let bucketSize ; let source ; if ( isOptionA ( options ) ) { source = Array . isArray ( _source ) ? _source : [ ... _source ] ; const minMax = scalar ( extent ( callbackFn ) ) ( source ) ; if ( minMax === undefined ) { return undefined ; } min = minMax [ 0 ] ; const max = minMax [ 1 ] ; const buckets = options . buckets ; bucketSize = ( max - min ) / buckets ; } else { source = _source ; min = options . min ; bucketSize = options . range ; } const histogram = { } ; let maxBucketID = 0 ; for ( const row of source ) { const value = callbackFn ( row ) ; const bucketID = Math . floor ( ( value - min ) / bucketSize ) ; if ( maxBucketID < bucketID ) { maxBucketID = bucketID ; } if ( histogram [ bucketID ] === undefined ) { histogram [ bucketID ] = [ ] ; } histogram [ bucketID ] . push ( row ) ; } const lastBucket = histogram [ maxBucketID ] ; const from = min + maxBucketID * bucketSize ; for ( let i = 0 ; i <= maxBucketID ; ++ i ) { if ( i === maxBucketID - 1 && lastBucket . every ( row => from === callbackFn ( row ) ) ) { yield { from : min + i * bucketSize , to : min + ( i + 1 ) * bucketSize , value : [ ... ( histogram [ i ] || [ ] ) , ... lastBucket ] } ; break ; } yield { from : min + i * bucketSize , to : min + ( i + 1 ) * bucketSize , value : histogram [ i ] || [ ] } ; } } ; } export function histogram < T > ( histogramByFn , options ) ; export function histogram < T > ( source , histogramByFn , options ) ; export function histogram < T > ( s_or_hf , hf_or_b , options ? ) { return isSource ( s_or_hf ) ? histogramGen < T > ( hf_or_b as HistogramFn < T > , options ! ) ( s_or_hf ) : histogramGen < T > ( s_or_hf as HistogramFn < T > , hf_or_b as Options ) ; }