Skip to content

N (Number)

The 16 dual Number operations appear with both shapes in the complete dual-call catalogue.

sum(nums: readonly number[]): number
mean(nums: readonly number[]): Option<number>
median(nums: readonly number[]): Option<number>
variance(nums: readonly number[]): Option<number>
standardDeviation(nums: readonly number[]): Option<number>
min(nums: readonly number[]): Option<number>
max(nums: readonly number[]): Option<number>
minMax(nums: readonly number[]): Option<readonly [number, number]>

Every partial aggregate also has an explicit *OrUndefined variant. Use the *NonEmpty variants when a readonly non-empty tuple proves a result exists, and the sample-statistic *AtLeastTwo variants when two inputs are required.

percentile(nums: readonly number[], p: number): Option<number>
percentile(p: number): (nums: readonly number[]) => Option<number>
percentileOrUndefined(nums: readonly number[], p: number): number | undefined
percentileOrUndefined(p: number): (nums: readonly number[]) => number | undefined
percentileNonEmpty(nums: readonly [number, ...number[]], p: number): number
percentileNonEmpty(p: number): (nums: readonly [number, ...number[]]) => number
clamp(value: number, min: number, max: number): number
clamp(min: number, max: number): (value: number) => number
dotProduct(a: readonly number[], b: readonly number[]): number
dotProduct(b: readonly number[]): (a: readonly number[]) => number
isEven(n: number): boolean
isOdd(n: number): boolean
import { pipe } from '@stopcock/fp'
import * as A from '@stopcock/fp/array'
import * as N from '@stopcock/fp/number'
import * as O from '@stopcock/fp/option'
// stats on response times
const times = [120, 95, 200, 88, 150, 300, 110] as const
pipe(
N.mean(times),
O.getOrElse(() => 0),
) // ~151.9
N.medianNonEmpty(times) // 120
N.standardDeviationNonEmpty(times) // ~68.6
N.percentileNonEmpty(times, 95) // 300, direct data-first
pipe(times, N.percentileNonEmpty(95)) // 300, curried data-last
// clamp user input
pipe(userAge, N.clamp(0, 150))
// average score, ignoring zeros
pipe(
scores,
A.filter((s) => s > 0),
N.mean,
)
// feature vector similarity
N.dotProduct([1, 0, 1], [0, 1, 1]) // 1, direct data-first
pipe([1, 0, 1], N.dotProduct([0, 1, 1])) // 1, curried data-last