Mapping to mixtures of Int64 & Float64

I have a function that can produce either Int64 or Float64 and I would like to map it to an array to be summed:

f(s) = parse(rand([Float64, Int64]), s)
a = rand(string.('0':'9'), rand([0,1,5]))
map(f, a) |> sum

If a is empty this fails because in that case, map produces an array of Any which cannot be summed.

The shortest solution that I can think of is:

map(f, a) |> Vector{Real} |> sum

but it just feels wrong to typecast everything (My application is not performance sensitive, so performance wise this is okay).

The other solutions that I can think of are:

map(f, a) |> (x -> isempty(x) ? Int64[] : x) |> sum

and

map(f, a) |> isempty(x) ? 0 : sum(x)

Iā€™m just curious to know if someone has a better solution.

Not sure if you are focused on the sum, but if so:

sum(f,a,init=0)
2 Likes

Thank you, the sum is important to me, so this is a better solution.

How about sum(float āˆ˜ f, a)?

sum(float āˆ˜ f, String[]) produces a stacktrace. It is important that it can handle the empty array case.

Note that this will be relatively slow in Julia because it is type unstable. Why not just return a Float64 in all cases?

(Contrary to popular misconception, integers are represented exactly by Float64 values, up to \pm 2^{53}, so you donā€™t generally improve accuracy by using Int to store integers.)

10 Likes

Well the stacktrace actually also tells you what went wrong and how to fix it right on the top:

julia> sum(floatāˆ˜f, String[])
ERROR: MethodError: reducing over an empty collection is not allowed; consider supplying `init` to the reducer
Stacktrace:
...

so all you need to do is to set init:

julia> sum(floatāˆ˜f, String[]; init=0.0)
0.0

Thank you, I was not aware of this, and according to this thread +, -, *, / and sqrt all preserve this precision. I will certainly consider this in the future, but I do need to work on being comfortable with this after 30 years of having the ā€œmisconceptionā€.

Thanks for challenging my old habits, it is nice to see a well respected programmer confident in using Float64 to represent integers. I will keep this in mind in the future, but right now I prefer not to change that part of the code.

Yes, I did see this, but I donā€™t see how that would be better than sum(f, String[], init=0) as proposed by @laborg .

Not much, on my benchmarks it is even a bit slower. But the underlying idea remains interesting: preserve type-stability wherever possible.
For example, init = 0.0 is better than init = 0 at least on papier, because the sum will end up being a Float64 and not an Int, so itā€™s better to initialize it that way. See also Performance Tips Ā· The Julia Language

1 Like