Yes, that’s true. It would be nice to have a macro which achieves similar functionality, i.e just evaluates only the code inside $(...)
. I don’t think that would be hard. Atleast for me, I have needed to use @eval
for this purpose frequently for evaluating some code which I need to pass to another macro. But I haven’t seen this proposed anywhere.
@heliosdrm, that is really nice.
We can then even broadcast Printf
to arrays using your solution:
v = rand(10)
f = Ref(Printf.Format("%5.2f"));
Printf.format.(f,v)
Also, simply map
:
map(x->@printf("%9.3f ",x), (1.0,2.0,3.0,4.0));
1.000 2.000 3.000 4.000
One more way with piping:
(1.0,2.0,3.0,4.0).|>(x->@sprintf("%9.3f",x))|>join
" 1.000 2.000 3.000 4.000"
I like this way as well:
julia> using Printf
julia> myformat(x) = @sprintf("%5.2f",x)
myformat (generic function with 1 method)
julia> x = rand(3);
julia> println(myformat.(x)...)
0.15 0.68 0.58
A quick thing, is it possible to print these stuff in a txt file?
I tried things like
f = Printf.Format("%9.3f"^4)
io = open("myfile.txt", "w")
for i in 1:10
@printf(io, f, 1,2,3,4)
end
close(io)
But it does not work.
I expect to have a file called myfile.txt in which it should have such 5 lines,
1.000 2.000 3.000 4.000
1.000 2.000 3.000 4.000
1.000 2.000 3.000 4.000
1.000 2.000 3.000 4.000
1.000 2.000 3.000 4.000
Thank you!
Note that if you are writing tabular data you can just use CSV.jl and Dataframes. Writing and reading text files can be quite complicated (lots of corner cases) so it’s better to use a library that is well tested.
@CRquantum, you could write like this (added carriage return for better formatting):
f = Printf.Format("%9.3f"^4*"\n")
io = open("myfile2.txt", "w")
for i in 1:10
Printf.format(io, f, 1,2,3,4)
end
close(io)
Thank you very much!
One more question, in the exactly the same example in the quote, if I put 1, 2, 3, 4 as an array a
a = [1.0, 2.0, 3.0, 4.0]
Then
Printf.format(io, f, a)
give ma an error.
Is there a way, exactly the same as this example, just that I could print array a instead of manually inputting 1,2,3,4 here?
This could be very useful because in the code it was very likely that we need to print some array with certain format.
In this case, have you tried the broadcasting solution above but without Ref
and replacing by the longer formatting sequence?
Thank you very much!
Yes I tried,
a = [1.0, 2.0, 3.0, 4.0]
f = Ref(Printf.Format("%5.2f"));
str = Printf.format.(f,a)
This gives me a 4-element Vector{String} which should be correct. However, when I write to a file by,
io = open("fileout.txt", "a")
write(io, str)
close(io)
It gives an error
`write` is not supported on non-isbits arrays
It seems write can only operator on one string? I am sure write can handle an array but I am not sure how to do it.
@CRquantum, you can add join
:
(using also join trick from @gustaphe):
a = [1.0, 2.0, 3.0, 4.0]
f = Ref(Printf.Format("%5.2f"));
open("fileout0.txt", "a") do io
join(io, Printf.format.(f,a))
end
Now I want a join(io::IO, f::Format , x, delim)
method…
join
takes iterables, so something like
let f = Printf.Format("%5.2f")
join(io, (Printf.format(f, a) for a in a))
end
should work fine.
Yes, but that generates strings. format
can operate on an IO
, so it wouldn’t be too hard to define such a function that doesn’t go via strings at all.
You are right. For avoiding even the intermediate strings, something like
function join2(io, f, itr, delim, last = delim)
for (i, a) in enumerate(a)
i == 0 || print(io, delim)
f(io, a)
end
print(io, last)
end
which takes a two-argument function but encapsulates the logic of join
would be nice.
Swap the first two arguments and you can do
delimiter="\t"
numbers=randn(20)
fmt=Format("%.2f")
open("file.tsv", "w") do file
join(file, numbers, delimiter) do io, x
format(io, fmt, x)
end
end
Not sure why you’d want to, but it looks pretty cool.
I’m confused about this one. When I tried it I got
julia> x=rand(3);
julia> fmt=Printf.Format("%.2f");
julia> Printf.format(fmt,x...)
ERROR: ArgumentError: mismatch between # of format specifiers and provided args: 1 != 3
What have I missed?
Your format string only has one specifier, so it will only work on one argument. Depending on what output you’re expecting, there’s options like
julia> fmt=Printf.Format("%.2f"^3); # equivalent to "%.2f%.2f%.2f"
julia> Printf.format(fmt, x...)
"0.030.050.21"
or
julia> fmt=Printf.Format("%.2f");
julia> Printf.format.(Ref(fmt),x)
3-element Vector{String}:
"0.03"
"0.05"
"0.21"