# Reverse multidimensional array

Hey,

recently I wanted to reverse a multidimensional array. I didn’t find a built-in solution but only this post on StackOverflow.

I was wondering what’s a proper implementation. I came up with the following. `reverse_2` is the the one from SO, but it’s horribly slow because it is copying everything for each reverse call again.
`reverse_all` and `reverse_all_view` are basically the same, except the `@view`.

``````function reverse_all(arr::AbstractArray, dims=1:ndims(arr))
return arr[reverse_all_indices(arr, dims)...]
end

function reverse_all_view(arr::AbstractArray, dims=1:ndims(arr))
return @view arr[reverse_all_indices(arr, dims)...]
end

function reverse_all_indices(arr, dims=1:ndims(arr))
out = []
for i in 1:ndims(arr)
push!(out, 1:size(arr)[i])
end

for d in dims
out[d] = size(arr)[d]:-1:1
end

return out
end

function reverse_2(arr)
for d = 1:ndims(arr)
arr = reverse(arr, dims=d)
end
return arr
end
``````

I often find myself writing code to construct the range expressions. Is there a better way? I’m aware of `CartesianIndices` but often I don’t find them easier.

``````julia> x = randn((1000, 12, 122, 140));

julia> @time y = reverse_all(x);
0.988784 seconds (14 allocations: 1.527 GiB, 0.67% gc time)

julia> @time y_v = reverse_all_view(x);
0.000014 seconds (12 allocations: 528 bytes)

julia> @time y_2 = reverse_2(x);
32.074907 seconds (817.91 M allocations: 18.302 GiB, 7.29% gc time)

julia> y == y_2 == y_v
true
``````

Thanks,

Felix

`reverse(A; dims=3)` ?

Check a bit further down the page in the docs for `reverse`.

Hm, I don’t think that works.
According to the manual it only reverses the dims dimension, not all dimensions.

That’s the reason to use the loop in `reverse_2`.

Sure, you didnt say all dimensions until further down than I read

With a matrix you can use `rot180` for that.

Julia 1.6’s `reverse` allows defining a tuple with several dimensions to reverse.
Is this what you require:

``````julia> M=[i+j for i in -3:0, j in -1:1]
4×3 Matrix{Int64}:
-4  -3  -2
-3  -2  -1
-2  -1   0
-1   0   1

julia> reverse(M; dims=(1,2))
4×3 Matrix{Int64}:
1   0  -1
0  -1  -2
-1  -2  -3
-2  -3  -4
``````
3 Likes

Nice, sounds good!

I’ll need to check whether it creates a view und what’s the performance in comparison to above implementation.

It doesn’t create a view, it makes a copy. You can also do `reverse!` to work in-place — this is the fastest option (that actually moves data) for large arrays.

Note also that the default is to reverse all the dimensions, so if that is what you want then you can simply do `reverse(a)` or `reverse!(a)`.

``````julia> @btime reverse_all(\$x);
1.152 s (14 allocations: 1.53 GiB)

julia> @btime reverse(\$x);
1.171 s (3 allocations: 1.53 GiB)

julia> @btime reverse!(\$x);
385.043 ms (0 allocations: 0 bytes)
``````

PS. Implementing multidimensional `reverse!` is fun and surprisingly compact, heavily using `CartesianIndices` tricks and recursion over the dimension.

4 Likes