View on Julia array using sliding window

Viewed 539

What is the most efficient way to create a view on array using, for example, sliding window=2

Let's say we have:

x = collect(1:1:6)
# 1 2 3 4 5 6

And I want to create a view like this:

# 1 2
# 2 3
# 3 4
# 4 5
# 5 6

So far I found only this option, but not sure if it's an optimal one:

y = Array{Float32, 2}(undef, nslides, window)
@inbounds for i in 1:window
    y[:, i] = @view x[i:end-(window-i)]
end
2 Answers

The one liner is:

view.(Ref(x), (:).(1:length(x)-1,2:length(x)))

Testing:

julia> x=collect(1:6);

julia> view.(Ref(x), (:).(1:length(x)-1,2:length(x)))
5-element Array{SubArray{Int64,1,Array{Int64,1},Tuple{UnitRange{Int64}},true},1}:
 [1, 2]
 [2, 3]
 [3, 4]
 [4, 5]
 [5, 6]

Explanation:

  • creation of views is vectorized by the dot operator .
  • we do not want to vectorize on elements of x so use Ref(x) instead
  • (:) is just a shorter form for UnitRange and again we use the dot operator . to vectorize

I used 2 as the Window size but of course you can write view.(Ref(x), (:).(1:length(x)-(window-1),window:length(x)))

EDIT:

If you want rather a library function this would work for you:

julia> using ImageFiltering

julia> mapwindow(collect, x, 0:1,border=Inner())
5-element OffsetArray(::Array{Array{Int64,1},1}, 1:5) with eltype Array{Int64,1} with indices 1:5:
 [1, 2]
 [2, 3]
 [3, 4]
 [4, 5]
 [5, 6]

Of course you could put them the function that you want to run on the sliding window rather than just collect.

One solution with a package (well, with my package) is this:

julia> using Tullio

julia> x = 1:6; window = 2;

julia> @tullio y[r,c] := x[r+c-1]  (c in 1:window)
5×2 Matrix{Int64}:
 1  2
 2  3
 3  4
 4  5
 5  6
Related