# In-place mapslices?

**URL:** <https://discourse.julialang.org/t/in-place-mapslices/126415>\
**Category:** General Usage\
**Tags:** views, inplace\
**Created:** [February 28, 2025, 7:11am UTC](https://discourse.julialang.org/t/in-place-mapslices/126415 "2025-02-28T07:11:21Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)\
**Post date:** [February 28, 2025, 7:11am UTC](https://discourse.julialang.org/t/in-place-mapslices/126415/1 "2025-02-28T07:11:21Z")

</div>

I want to apply a function that operates on a vector, to each column of a matrix. So, I use `mapslices()`. But, how to modify the matrix in-place?

The following is a failed attempt:

```julia
function f!(xs)
  a = xs[1]
  @. xs = xs / a
end

xs = Float64.([3,4,5])
f!(xs)
display(xs) # Elements of xs have been changed

xs = Float64.(hcat([3,4,5],[6,7,8]))
ys = mapslices(f!, xs, dims=1)
display(xs) # -> Not changed
display(ys)

xs = Float64.(hcat([3,4,5],[6,7,8]))
@views ys = mapslices(f!, xs, dims=1)
display(xs) # -> Not changed
display(ys)

```

Even the `@views` macro doesn’t seem to work.

I wonder why `mapslices()` doesn’t pass a view ? Even if the function doesn’t change the contents of the array, a view wouldn’t change the results . . . or would it?

---

<div class="post-metadata">

**Author:** ![alfaromartino](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alfaromartino/32/52986_2.png) [@alfaromartino](https://discourse.julialang.org/u/alfaromartino)\
**Post date:** [February 28, 2025, 11:06am UTC](https://discourse.julialang.org/t/in-place-mapslices/126415/2 "2025-02-28T11:06:59Z")

</div>

Don’t know if your question is about `mapslices` more generally. But in case your question is about how to achieve the result with a simple syntax, you could use

```julia
foreach(f!, eachcol(xs))

```

As far as I remember, `mapslices` wasn’t still polished and is less performant than other options. For example, using `sum` in the following example is more performant:

```julia
using BenchmarkTools
xs = rand(100,100)

@btime mapslices(sum, $xs; dims=1) # 4.836 μs (15 allocations: 2.125 KiB)
@btime sum($xs; dims=1) # 767.667 ns (1 allocations: 896 bytes)

```

---

<div class="post-metadata">

**Author:** ![eldee](https://avatars.discourse-cdn.com/v4/letter/e/b5a626/32.png) [@eldee](https://discourse.julialang.org/u/eldee)\
**Post date:** [February 28, 2025, 12:29pm UTC](https://discourse.julialang.org/t/in-place-mapslices/126415/3 "2025-02-28T12:29:18Z")

</div>

> [@ryofurue](#):
>
> I wonder why `mapslices()` doesn’t pass a view ?

I would expect `mapslices`, like `map`, to return a new `Array`, which in turn sort of implicitly implies that you don’t want to mutate the original data.

In any case, the fact that `mapslices` does not operate on views and does not mutate the input, is explicitly mentioned in the docs

```julia-repl
help?> mapslices
...
  Notice that in eachslice(A; dims=2), the specified dimension is the one without a colon in the slice. This is
  view(A,:,i,:), whereas mapslices(f, A; dims=(1,3)) uses A[:,i,:]. The function f may mutate values in the slice
  without affecting A.

```

---

<div class="post-metadata">

**Author:** ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)\
**Post date:** [March 1, 2025, 2:58pm UTC](https://discourse.julialang.org/t/in-place-mapslices/126415/4 "2025-03-01T14:58:13Z")

</div>

> [@alfaromartino](#):
>
> Don’t know if your question is about `mapslices` more generally. But in case your question is about how to achieve the result with a simple syntax, you could use
> 
> ```julia
> foreach(f!, eachcol(xs))
> 
> ```

Thanks. In that case, I need to change my example. In my actual program, I work on 2D slices of a 3D array:

```julia
function f!(arr2D) #
  a = arr2D[1,1]
  @. arr2D = arr2D / a
end
arr3D = rand(3, 4, 5)
mapslices(f!, arr3D, dims=3)

```

I’m reading the documentation of `foreach` and I think I need to be able to create an iterator that gives the 2D slices: `arr3D[:, :, 1]`, `arr3D[:, :, 2]`, . . . and I guess it’s `eachslice()` . . . So,

```julia
function f!(arr2D) #
  a = arr2D[1,1]
  @. arr2D = arr2D / a
end
arr3D = rand(4, 3, 2)
foreach(f!, eachslice(arr3D, dims=3))

```

which works!

So, I wonder what the raison d’être of `mapslices()` is, then . . . `foreach()` is more general because it can work on any iterator. Perhaps, `mapslices()` gains more performance by assuming that its argument is an array?

---

<div class="post-metadata">

**Author:** ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)\
**Post date:** [March 1, 2025, 3:16pm UTC](https://discourse.julialang.org/t/in-place-mapslices/126415/5 "2025-03-01T15:16:16Z")

</div>

> [@eldee](#):
>
> I would expect `mapslices`, like `map`, to return a new `Array`, which in turn sort of implicitly implies that you don’t want to mutate the original data.

I did and do expect that, too, but _I also expect that `mapslices!` existed!_

I’ve just searched this forum for `map!()` and found a discussion thread about some confusion and difficulty.

There must be something I don’t understand. I thought that `map` and `map!` were trivial and likewise `mapslices` and `mapslices!` were trivial, just like the pair of `read()` and `read!()`.

---

<div class="post-metadata">

**Author:** ![eldee](https://avatars.discourse-cdn.com/v4/letter/e/b5a626/32.png) [@eldee](https://discourse.julialang.org/u/eldee)\
**Post date:** [March 1, 2025, 4:46pm UTC](https://discourse.julialang.org/t/in-place-mapslices/126415/6 "2025-03-01T16:46:43Z")

</div>

> [@ryofurue](#):
>
> There must be something I don’t understand. I thought that `map` and `map!` were trivial

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-repl
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-repl
julia> map!(a -> 2a, x, x); x
3-element Vector{Float64}:
 0.1806017811667775
 1.3392022070061778
 0.6600501140936825

```

but the documentation explicitly warns against this:

```julia-repl
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-repl
julia> broadcast!(a -> 2a, x, x)
3-element Vector{Float64}:
 0.361203562333555
 2.6784044140123555
 1.320100228187365

```

which is equivalent to

```julia-repl
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:

```julia
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
=#

```

> [@ryofurue](#):
>
> I wonder what the raison d’être of `mapslices()` is

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.

```julia
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.

```
