diff --git a/packages/strings/src/float.ts b/packages/strings/src/float.ts index 669c3d0178..f518a496c0 100644 --- a/packages/strings/src/float.ts +++ b/packages/strings/src/float.ts @@ -3,19 +3,22 @@ import type { Stringer } from "./api"; import { padLeft } from "./pad-left"; /** - * Returns {@link Stringer} which formats numbers to given precision. - * Exceptions: + * Returns {@link Stringer} which formats numbers to given precision. If + * `special` is true, then exceptional handling for: * * - NaN => "NaN" * - Infinity => "+/-∞" * * @param len - number of fractional digits - * @kind function + * @param special - true, if special handling for NaN/Infinity values */ export const float: ( - prec: number -) => Stringer = memoizeJ((prec) => (x: number) => - nanOrInf(x) || x.toFixed(prec) + prec: number, + special?: boolean +) => Stringer = memoizeJ((prec, special = false) => + special + ? (x: number) => nanOrInf(x) || x.toFixed(prec) + : (x: number) => x.toFixed(prec) ); /** diff --git a/packages/strings/src/index.ts b/packages/strings/src/index.ts index 299a9d57f5..72e3b83cd7 100644 --- a/packages/strings/src/index.ts +++ b/packages/strings/src/index.ts @@ -9,6 +9,7 @@ export * from "./float"; export * from "./format"; export * from "./groups"; export * from "./hollerith"; +export * from "./int"; export * from "./interpolate"; export * from "./join"; export * from "./pad-left"; @@ -28,5 +29,6 @@ export * from "./truncate"; export * from "./truncate-left"; export * from "./units"; export * from "./uuid"; +export * from "./vector"; export * from "./wrap"; export * from "./word-wrap"; diff --git a/packages/strings/src/int.ts b/packages/strings/src/int.ts new file mode 100644 index 0000000000..9e7d2a55eb --- /dev/null +++ b/packages/strings/src/int.ts @@ -0,0 +1,10 @@ +import { memoizeJ } from "@thi.ng/memoize"; +import type { Stringer } from "./api"; + +export const int: Stringer = (x) => String(Math.trunc(x)); + +export const intLocale: ( + locale?: string +) => Stringer = memoizeJ((locale) => (x) => + Math.trunc(x).toLocaleString(locale) +); diff --git a/packages/strings/src/vector.ts b/packages/strings/src/vector.ts new file mode 100644 index 0000000000..38f9b4afd6 --- /dev/null +++ b/packages/strings/src/vector.ts @@ -0,0 +1,55 @@ +import { isNumber } from "@thi.ng/checks"; +import { memoizeJ } from "@thi.ng/memoize"; +import type { Stringer } from "./api"; +import { float } from "./float"; + +/** + * Higher order formatter for n-D vectors, with each element formatted using + * `prec` and using optional delimiter and pre/postfixes. + * + * @size - vector size (optimized for size 1-4) + * @prec - precision (see {@link float}) or existing number formatter + * @delim - delimiter (default: `,`) + * @pre - prefix (default: `[`) + * @post - prefix (default: `]`) + */ +export const vector: ( + size: number, + prec?: number | Stringer, + delim?: string, + pre?: string, + post?: string +) => Stringer> = memoizeJ( + ( + size: number, + prec: number | Stringer = 3, + d = ",", + pre = "[", + post = "]" + ) => { + const f = isNumber(prec) ? float(prec) : prec; + switch (size) { + case 1: + return (v: ArrayLike) => `${pre}${f(v[0])}${post}`; + case 2: + return (v: ArrayLike) => + `${pre}${f(v[0])}${d}${f(v[1])}${post}`; + case 3: + return (v: ArrayLike) => + `${pre}${f(v[0])}${d}${f(v[1])}${d}${f(v[2])}${post}`; + case 4: + return (v: ArrayLike) => + `${pre}${f(v[0])}${d}${f(v[1])}${d}${f(v[2])}${d}${f( + v[3] + )}${post}`; + default: + return (v: ArrayLike) => { + const res = []; + for (let i = 0; i < v.length; i++) { + res.push(f(v[i])); + } + return `${pre}${res.join(d)}${post}`; + }; + } + } +);