Page 1 of 1

Align columns of numbers by decimal point

Posted: Thu Jul 20, 2006 9:11 am
by cormullion
Is there a clever way to align numbers by the decimal point when using the println and format functions?

Code: Select all

 205.492  
 201.729  
 201.38   
  -5.38672
  -1.38724
-158.966  
 123.63   
Or do I convert them to strings first, then calculate the amount of leading and trailing spaces to use?

Posted: Thu Jul 20, 2006 11:33 am
by Lutz
format is used for this:

Code: Select all

> (map (fn (num) (format "%10.2f" num)) '(1.22 123.456 12345.567))
("      1.22" "    123.46" "  12345.57")
> 
The 10 tells the format spec to make the whole field 10 positions long. This includes the decimal point and all leading spaces. The 2 tells it to format for 2 decimals begind the point. As you can see in the example, it also rounds numbers.

This works only when all numbers are formatted for the same amount of decimals after the point. In your case you could make a strings with a high count after the decimal count:

Code: Select all

> (map (fn (num) (format "%10.5f" num)) '(1.2 123.45 12345.567))
("   1.20000" " 123.45000" "12345.56700")
> 
... and than replace trailing 0's in those strings with some clever regular expression ;)

Lutz

Posted: Thu Jul 20, 2006 11:45 am
by Lutz
.... like this:

Code: Select all

> (replace {(0+)$} "12345.567000" (dup " " (length $1)) 0)
"12345.567   "
> 
the pattern {(0+)$} finds one or more trailing zeros and replaces them with the same number of spaces. Putting it all together:

Code: Select all

(map (fn (num) (replace {(0+)$} 
                          (format "%12.5f" num) 
                          (dup " " (length $1)) 0) ) 
          '(1.2 123.45 12345.567))
=>("     1.2    " "   123.45   " " 12345.567  ")
Lutz

Posted: Thu Jul 20, 2006 12:13 pm
by cormullion
Of course - now I see you do it it looks natural. For some reason I hadn't thought of trying to capture the results of format and continuing to work on them, I've just been using format in print statements.

Thanks Lutz!

Posted: Thu Jul 20, 2006 4:09 pm
by cormullion
I ended up using this:

Code: Select all

(replace {(0+)[^0-9|.]} temp (dup " " (length $1)) 0)
hoping to strip 0's if not followed by more digits or decimal point. How long did it take for you guys to become blackbelts in RegExp-Do? :-) Takes me an hour per regex...

Posted: Fri Jul 21, 2006 4:54 am
by m i c h a e l
I only have my yellow belt in regex, so I'm around the same level as you, cormullion.

I remember a quote having to do with someone having a problem that he decided to solve with regular expressions. "Now," as the saying goes, "he has two problems." ;-)

m i c h a e l