Writing array to file with format

I’m trying to write an array with predefined format to a file. In Fortran this is :

do i=size(A,1)
    write(10,'(1000f9.5)')A(i,:)
enddo

in Julia this is:

for row in eachrow(A)
    write(io,row)
end

but (contrary to python or fortran) write does not directly accept formats (or I couldn’t find how).

I am aware of Printf and of @printf and of @sprintf and of this thread How to repeat the format in @printf? but I have not been able to find a neat solution or a clear example that would not involve joins, broadcasting functions, etc. Am I missing something?

thanks, Andres

What’s wrong with a loop?

for i = axes(A, 1)
    for j = axes(A, 2)
        @printf(io, "%9.5f", A[i,j])
    end
    println(io)
end

write in Julia is for raw binary output, not for text representations of numeric data.

4 Likes

That’s definitely one thing where Fortran has a simpler syntax than any other language I know.

In Julia I do this:

julia> using Printf

julia> fmt(x) = @sprintf("%9.5f",x)
fmt (generic function with 1 method)

julia> x = rand(3);

julia> println(fmt.(x)...)
  0.76353  0.61711  0.72342

and yes, it involves broadcasting, splatting, etc. I don’t know of any much cleaner alternative (there are ways to make it faster, but usually that’s not important).

(as mentioned above, the write function in Fortran is println in julia, write in Julia is something else).

1 Like

This seems like a prime example of why contorting yourself to avoid writing loops is a bad habit in programming. Not only is allocating 1000 strings and splattting them just to write them terrible for performance, but it’s arguably a lot less clear than just writing a 3-line loop.

Also note that the OP asked for a solution “that would not involve joins, broadcasting functions, etc” (emphasis added).

2 Likes

I know about the horrible performance limitations of that, but I have to be sincere here, I didn’t find that loop clear (after some thought, now I get it :slight_smile: ). There are quite a few assumptions there which may be obvious for some.

For instance, that @printf(io, ...) will write row-wise, and that println(io) is being used to print a single new line character. (It would be clearer for me if you had used println(io,'\n').

What is curious here is that this tentative to “vectorize” the writing is perhaps one unique example where Fortran provides a “vectorized” alternative that, indeed, promotes that kind of bad habit. And in Fortran one gets used to that just because the standard write includes the new line character, such that it is less natural to write a double loop than a single loop with a row-vectorized writing in the middle.

By the way, if I wanted to print that on the REPL, what io should be? (edit: found it: io = stdout)

1 Like

Thank you both @lmiq and @stevengj . Both solutions are natural and elegant. I am not agains loops (I did not mention loops; I did mention broadscats). Anyway all previous solutions that I could see where extremely complicated.

Fortran (like Julia) provides many vectorized options equivalent e.g. to .= and I was surprised not to find them for printing in Julia.

1 Like

Yes, true, but most of the vectorized operations of modern fortran translate quite clearly to equivalent loops. Specifically when writing files the vectorized operation is sort of forced upon one, since a double loop writing one element at a time, row-wise, is very unnatural in Fortran.

You could also use something like PrettyTables.jl which has lots of utilities for this. It is mostly for display, but you can output to file also.

That writes two newlines. println(io) is equivalent to print(io, '\n').

If you omit the io argument entirely, it defaults to stdout.

1 Like

There are lots of vectorized array I/O routines in Julia, but they are mostly for read/writing standard formats (CSV, HDF5, raw binary, …). Fortran 77 style fixed-width ASCII formats, which date back to the days of card readers, are much less common these days for storage, and there are better options if you simply want pretty printing.

(That being said, there is still some interest in fixed-width formats, e.g. there is an open issue to add this to CSV.jl. I’m guessing that eventually there will be optimized library support, but it doesn’t seem like something that is a burning issue for many developers.)

Fixed-width tables appear pretty often in the wild IME, see my Alexander Plavin / FixedWidthTables.jl · GitLab package for convenient and general reading of them. Potentially, writing could be in scope as well, it’s just that I personally never needed to do that.

1 Like

Same stuff but using foreach:

using Printf
A = rand(100,10)

io = IOBuffer()
for r in eachrow(A)
    foreach(x -> @printf(io, "%9.5f", x), r)
    println(io)
end
println(String(take!(io)))