To clarify, should it be helpful, map!
is also not intended to alter the input: you have to specify another collection destination
, distinct from the input.
julia> x = rand(3); y = similar(x); x
3-element Vector{Float64}:
0.09030089058338875
0.6696011035030889
0.33002505704684126
julia> map!(a -> 2a, y, x);
julia> x
3-element Vector{Float64}:
0.09030089058338875
0.6696011035030889
0.33002505704684126
julia> y
3-element Vector{Float64}:
0.1806017811667775
1.3392022070061778
0.6600501140936825
In principle you could use
julia> map!(a -> 2a, x, x); x
3-element Vector{Float64}:
0.1806017811667775
1.3392022070061778
0.6600501140936825
but the documentation explicitly warns against this:
help?> map!
...
│ Warning
│
│ Behavior can be unexpected when any mutated argument shares memory with any other argument.
( You could use broadcast!
in this case
julia> broadcast!(a -> 2a, x, x)
3-element Vector{Float64}:
0.361203562333555
2.6784044140123555
1.320100228187365
which is equivalent to
julia> x .= 2 .* x
3-element Vector{Float64}:
0.72240712466711
5.356808828024711
2.64020045637473
.)
Note that in this example we are using a non-mutating function (f = a -> 2a
). If you have a mutating function f!
, map(f!, ...)
and map!(f!, ...)
make little sense since we don’t want to store the outputs* of f!
into some (new) collection, we just want to apply f!
everywhere. (*In fact, it makes perfect sense to make f!
return nothing
.) To apply f!
to each element, use foreach
, cf. @alfaromartino 's reply.
Alternatively, you could of course also just use a simple for-loop, which to me seems the clearest and easiest option:
function f!(arr2D)
a = arr2D[1,1]
@. arr2D = arr2D / a
end
arr3D = rand(2, 2, 3)
for i = axes(arr3D, 3)
f!(@view arr3D[:, :, i])
end
#= arr3D now contains e.g.
2×2×3 Array{Float64, 3}:
[:, :, 1] =
1.0 2.10948
6.01437 6.37489
[:, :, 2] =
1.0 1.16381
0.00573419 1.19772
[:, :, 3] =
1.0 0.0260569
0.403835 0.511961
=#
The natural alternative would be map(..., eachslice(...))
. But this is not equivalent to mapslices(..., ...)
as the former works on view
s, and the latter on copies.
function f!(xs)
a = xs[1]
@. xs = xs / a
# (Note that f! implicitly returns xs)
end
xs = Float64.(hcat([3,4,5],[6,7,8]))
ys = mapslices(f!, xs, dims=1)
display(xs) # -> Not changed
xs = Float64.(hcat([3,4,5],[6,7,8]))
ys = map(f!, eachslice(xs, dims=1))
display(xs) # -> Changed
# (By the way, ys here consists of views of (the mutated) xs. I.e if you alter xs, ys is also changed.)
# Don't use map in this way though, as this is not how it's supposed to be used.