The Crystal Programming Language Forum

Variable width output number formatting

I’m missing something here.
I want to print out numerical values in an array, 10 per line, whose width field for each number is the digits size of the last/largest number in the array.

This will print out 10 number per line, with a width field of 3.

ary.each_with_index { |n, idx| print "%3d " % n; print "\n" if idx % 10 == 9 }

What I want to do is make the width format %3d adjustable to the length of the digits size of the largest/last number in the array, and tried doing it like this.

maxdigits = ary.last.digits
ary.each_with_index{ |n, idx| print "%#{maxdigits}d " % n; print "\n" if idx % 10 == 9 }

But this doesn’t work.
I want to do this as simple as possible, without using a macro.
I’m assuming I can dynamically change the formatting.
Is that so? How?

Try making that maxdigits = ary.last.digits.size

ary = Array.new(50, &.itself)
maxdigits = ary.last.digits.size
ary.each_with_index{ |n, idx| print "%#{maxdigits}d " % n; print "\n" if idx % 10 == 9 }
#  0  1  2  3  4  5  6  7  8  9
# 10 11 12 13 14 15 16 17 18 19
# 20 21 22 23 24 25 26 27 28 29
# 30 31 32 33 34 35 36 37 38 39
# 40 41 42 43 44 45 46 47 48 49

Alternatively, you can also pass the field width as another parameter: printf("%*d ", maxdigits, n)

printf is necessary because % receives only a single argument. It’s also more efficient than print + %, though.

Overall, this alternative saves 2 * ary.size string allocations.

Of course. :roll_eyes:

Learned something new, again.

Thanks to both.

1 Like

For width based on “largest number”, you could do something like width = arr.max.to_s.size.

1 Like

Or width = arr.max_of { |num| num.to_s.size }