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?
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).
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).
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 ). 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)
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.
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.
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.