sourcelibs/Format/src/Format.xtl

1⍝# Format: number formatting -- fixed decimals, thousands separators, 2⍝# percentages, aligned columns, text tables. 3⍝# Import it with an alias of your choice: "f:" u_se< "Format". 4⍝# Put libs/Format/src on XETAL_PATH ("just path"); the reference is libs/Format/docs. 5⍝# Names with l: are exported; those under h: are private to this file. 6⍝# 7⍝# X_eTaL's f_ormat has no width or precision yet (dyadic format is on 8⍝# its wish list): these build the text from the digits. A formatted 9⍝# list is a list of texts (Box Char), one per number, ready for 10⍝# f:c_olumn or f:t_able. 11 12ᵗ⁼u̲se< "Strings" 13"q:" u̲se< "Lists" 14 15digits ← ⎕D 16 17⍝## Fixed decimals 18 19⍝# The k decimal digits of a whole number d, leading zeros kept. 20ʰp̲added ← { k d → k = 0 ? ""◆ (1 + (k r̲eshape 10) e̲ncode d) s̲elect digits } 21 22⍝# One number with n decimals, rounded half away from zero. 23ʰo̲ne ← { n x → 24 s ← f̲loor 0.5 + (a̲bs f̲loat x) × f̲loat 10 ^ n 25 w ← s d̲iv 10 ^ n 26 sign ← ((x < 0) ∧ s > 0) r̲eplicate "-" 27 n = 0 ? sign c̲at f̲ormat w 28 sign c̲at (f̲ormat w) c̲at "." c̲at n ʰp̲added s m̲od 10 ^ n 29} 30 31⍝# n f_ixed v: each number of v with exactly n decimals (n >= 0). 32ˡf̲ixed ← { n v → '{ x → n ʰo̲ne x } m̲ap r̲avel v } 33 34⍝## Thousands and money 35 36⍝# A whole number >= 0 with a comma between each group of three digits: 37⍝# padded in front to a multiple of 3, cut into rows of 3, joined. 38ʰc̲ommas ← { w → 39 d ← f̲ormat w 40 p ← 3 × c̲eiling (f̲loat t̲ally d) ÷ 3.0 41 rows ← ((p d̲iv 3) c̲at 3) r̲eshape (n̲eg p) t̲ake d 42 ᵗt̲rimStart "," ᵗj̲oin '{ i → i s̲elect rows } m̲ap r̲ange p d̲iv 3 43} 44 45⍝# One number rounded to a whole number, its thousands separated. 46ʰg̲rouped ← { x → 47 w ← f̲loor 0.5 + f̲loat a̲bs x 48 (((x < 0) ∧ w > 0) r̲eplicate "-") c̲at ʰc̲ommas w 49} 50 51⍝# One number with n decimals and its thousands separated. 52ʰa̲mount1 ← { n x → 53 s ← f̲loor 0.5 + (a̲bs f̲loat x) × f̲loat 10 ^ n 54 w ← s d̲iv 10 ^ n 55 sign ← ((x < 0) ∧ s > 0) r̲eplicate "-" 56 n = 0 ? sign c̲at ʰc̲ommas w 57 sign c̲at (ʰc̲ommas w) c̲at "." c̲at n ʰp̲added s m̲od 10 ^ n 58} 59 60⍝# t_housands v: each number of v, rounded to a whole number, with its 61⍝# thousands separated by commas. 62ˡt̲housands ← { v → 'ʰg̲rouped m̲ap r̲avel v } 63 64⍝# n a_mount v: each number of v with n decimals and its thousands 65⍝# separated by commas (money: 2 f:a_mount 1324.69 is 1,324.69). 66ˡa̲mount ← { n v → '{ x → n ʰa̲mount1 x } m̲ap r̲avel v } 67 68⍝# n p_ercent v: each fraction of v as a percentage with n decimals. 69ˡp̲ercent ← { n v → '{ t → (d̲isclose t) c̲at "%" } m̲ap n ˡf̲ixed 100.0 × f̲loat v } 70 71⍝## Tables 72 73⍝# A list of texts as a character matrix, one per row, w wide. 74ʰr̲ows ← { w list → ((t̲ally list) c̲at w) r̲eshape q:r̲aze list } 75 76⍝# c_olumn list: the texts of a list right-aligned under each other (a 77⍝# character matrix), as numbers are set in a column. 78ˡc̲olumn ← { list → 79 w ← 'm̲ax r̲/ '{ t̲ally d̲isclose ⍵ } e̲ach list 80 w ʰr̲ows '{ t → w ᵗp̲adLeft d̲isclose t } m̲ap list 81} 82 83⍝# Whether a text reads as a number (set right-aligned in a table). 84ʰn̲umeric? ← { t → 0 = t̲ally t ? 0 = 1◆ '∧ r̲/ t m̲ember? ⎕D c̲at "-+.,%" } 85 86⍝# t_able cells: a matrix of texts (Box Char), its first row the 87⍝# header, as a character matrix: columns two spaces apart, each as wide 88⍝# as its widest text, a column of numbers (every cell under the header) 89⍝# right-aligned with its header, other columns left-aligned, a rule 90⍝# under the header. 91ˡt̲able ← { cells → 92 w ← 'm̲ax r̲/ '{ t̲ally d̲isclose ⍵ } e̲ach cells ⍝ each column's width 93 num ← '∧ r̲/ 1 d̲rop '{ ʰn̲umeric? d̲isclose ⍵ } e̲ach cells 94 ws ← r̲avel (s̲hape cells) r̲eshape w ⍝ each cell's width 95 ns ← r̲avel (s̲hape cells) r̲eshape num ⍝ each cell's alignment 96 cs ← r̲avel cells 97 p ← (s̲hape cells) r̲eshape '{ i → 98 n ← f̲irst i s̲elect ws 99 c ← d̲isclose i s̲elect cs 100 f̲irst i s̲elect ns ? n ᵗp̲adLeft c 101 n ᵗp̲adRight c 102 } m̲ap r̲ange t̲ally cs 103 rows ← '{ i → " " ᵗj̲oin i s̲elect p } m̲ap r̲ange t̲ally p 104 rule ← " " ᵗj̲oin '{ n → n r̲eshape "-" } m̲ap w 105 all ← (1 t̲ake rows) c̲at (e̲nclose rule) c̲at 1 d̲rop rows 106 (t̲ally rule) ʰr̲ows all 107}