How to align output in columns?

question

#1

I have the following script:

println("n \t n! \t\t Approximation \t\t Ratio")

for n in 1:10
    fact  = factorial(big(n))
    stir  = n^n * exp(-n) * sqrt(2 * π * n )
    ratio = Float32(fact/stir)
    println("$n \t $fact \t $stir \t $ratio")
end

This results in the following output:


n 	 n! 		 Approximation 		 Ratio
1 	 1 	 0.9221370088957891 	 1.0844376
2 	 2 	 1.9190043514889832 	 1.0422071
3 	 6 	 5.836209591345864 	 1.0280645
4 	 24 	 23.50617513289329 	 1.0210083
5 	 120 	 118.01916795759008 	 1.016784
6 	 720 	 710.0781846421849 	 1.0139729
7 	 5040 	 4980.395831612461 	 1.0119678
8 	 40320 	 39902.3954526567 	 1.0104656
9 	 362880 	 359536.87284194824 	 1.0092984
10 	 3628800 	 3.598695618741036e6 	 1.0083654

Which is the better approach for cases like this one when I want to print outputs in columns?


#2

Perhaps:

using DataFrame

df = DataFrame(n = Int[], n! = Int[], Approximation = Float64[], Ratio = Float64[])

for n in 1:10
    fact  = factorial(big(n))
    stir  = n^n * exp(-n) * sqrt(2 * π * n )
    ratio = Float32(fact/stir)
    push!(df, [n, fact, stir, ratio])
end

strwidths = [maximum(strwidth.(string.([df[:, i]; names(df)[i]]))) for i in 1:size(df, 2)]

io = IOBuffer()

# Print headers
for (i, header) in enumerate(names(df))
	print(io, rpad(header, strwidths[i]), "\t")
end
println(io)

for j in 1:size(df, 1)
	for i in 1:size(df, 2)
		print(io, rpad(df[j,i], strwidths[i]), "\t")
	end
	println(io)
end

print(String(take!(io)))

giving

n 	n!     	Approximation      	Ratio             	
1 	1      	0.9221370088957891 	1.084437608718872 	
2 	2      	1.9190043514889832 	1.04220712184906  	
3 	6      	5.836209591345864  	1.028064489364624 	
4 	24     	23.50617513289329  	1.0210082530975342	
5 	120    	118.01916795759008 	1.0167839527130127	
6 	720    	710.0781846421849  	1.0139728784561157	
7 	5040   	4980.395831612461  	1.0119677782058716	
8 	40320  	39902.3954526567   	1.0104656219482422	
9 	362880 	359536.87284194824 	1.0092984437942505	
10	3628800	3.598695618741036e6	1.0083653926849365	

The code is not very well polished but might give you a start.


#3

Thank you… I am sorry, I didn’t want you to write the whole code for me… I was just thinking there was something more concise… thank you for the the code and the many ideas on it…


#4

You might find it easier to use something like https://github.com/JuliaString/StringLiterals.jl,
and I think it gives cleaner, easier to read output than the other solution.

It is not registered, so you need to load it and it’s dependencies the first time as follows:

const loc = "https://github.com/JuliaString/"
for pkg in ("StrTables",
            "HTML_Entities", "LaTeX_Entities", "Unicode_Entities", "Emoji_Entities",
            "Format", "StringLiterals")
    Pkg.clone(string(loc, pkg, ".jl"))
end

Then you can write formatted output very succintly:

using StringLiterals

function out()
    pr"""n   \%8s("n!")   \%16s("Approximation")   \%10s("Ratio")\n"""
    for n in 1:10
        fact  = factorial(big(n))
        stir  = n^n * exp(-n) * sqrt(2 * π * n )
        ratio = Float32(fact/stir)
        pr"\%-3d(n) \%8d(fact)   \%16.8f(stir)   \%10.8f(ratio)\n"
    end
end

The output is:

n         n!      Approximation        Ratio
1          1         0.92213701   1.08443761
2          2         1.91900435   1.04220712
3          6         5.83620959   1.02806449
4         24        23.50617513   1.02100825
5        120       118.01916796   1.01678395
6        720       710.07818464   1.01397288
7       5040      4980.39583161   1.01196778
8      40320     39902.39545266   1.01046562
9     362880    359536.87284195   1.00929844
10   3628800   3598695.61874104   1.00836539

#5

Yeah, using seven packages and hard coding the alignments will indeed make the code shorter.


#6

Another option might be to use @printf


#7

Many packages depend on others - the only issue is that the packages are not yet registered.
No need to be snide.