Simultaneous access to the array and flow around before

I have a simple question that should have a simple answer, but I still canโ€™t think about it. I want to process an array, a certain number of elements at a time, and wrap around to the beginning.

Here is a diagram showing when n is 10 and three elements:

iterate 3 at a time

My attempts to write a simple iteration have still not worked: using % n gives me zeros that don't work with Julia single-indexing ... :)

+7
arrays iteration julia-lang
source share
4 answers

The mod1 function mod1 provided to provide the desired behavior:

 julia> mod1(1, 5) 1 julia> mod1(3, 5) 3 julia> mod1(5, 5) 5 julia> mod1(6, 5) 1 

It is very simple to make a function with the mod index:

 modindex(A, i) = A[mod1(i, length(A))] 

Or even your own index type with mod index:

 julia> immutable CircArray{T} <: AbstractArray{T,1} xs::Vector{T} end julia> Base.size(x::CircArray) = (length(x.xs),) julia> Base.getindex(x::CircArray, i) = x.xs[mod1(i, length(x.xs))] julia> A = CircArray([1:2:10;]) CircArray{Array{Int64,1}}([1,3,5,7,9]) julia> A[0] 9 julia> A[5] 9 julia> A[7] 3 

It is not too difficult to implement slicing on top of this. As DNF mentions in the comment, a clean and concise solution

 modindex(A, i) = A[mod1.(i, end)] 

or the equivalent for getindex , which handles both scalar indexing and slicing.


Change Since your question is mentioned in an iteration, I suggest that I would suggest a more general solution that also works with non-iterations for iteration purposes, using only functional iterations in Base :

 julia> threes(A) = let cy = cycle(A) take(zip(cy, drop(cy, 1), drop(cy, 2)), length(A)) end threes (generic function with 1 method) julia> for (a, b, c) in threes([1, 2, 3, 4, 5]) println(a, b, c) end 123 234 345 451 512 
+10
source share

Iterators.jl will give you a simple iterator accessing the array for several elements at a time:

 julia> for i in partition(1:15, 3, 1) @show i end i = (1,2,3) i = (2,3,4) i = (3,4,5) i = (4,5,6) i = (5,6,7) i = (6,7,8) i = (7,8,9) i = (8,9,10) i = (9,10,11) i = (10,11,12) i = (11,12,13) i = (12,13,14) i = (13,14,15) 

and, as Fengyang Wang suggested, the function mod1 performs a wrapping-to-start operation. just make a combination:

 julia> for i in partition(1:15, 3, 1) @show mod1.(collect(i), 10) end mod1.(collect(i),10) = [1,2,3] mod1.(collect(i),10) = [2,3,4] mod1.(collect(i),10) = [3,4,5] mod1.(collect(i),10) = [4,5,6] mod1.(collect(i),10) = [5,6,7] mod1.(collect(i),10) = [6,7,8] mod1.(collect(i),10) = [7,8,9] mod1.(collect(i),10) = [8,9,10] mod1.(collect(i),10) = [9,10,1] mod1.(collect(i),10) = [10,1,2] mod1.(collect(i),10) = [1,2,3] mod1.(collect(i),10) = [2,3,4] mod1.(collect(i),10) = [3,4,5] 
+4
source share

For

 a = [1,2,3,4,5] 

do

  repmat(a',5,2) 5x10 Array{Int64,2}: 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 

and then

 map(i -> [a[i,i], a[i,i+1], a[i,i+2]], 1:5) 5-element Array{Array{Int64,1},1}: [1,2,3] [2,3,4] [3,4,5] [4,5,1] [5,1,2] 

Bonus

If you want to find out, or a memory problem (repmat is not very memory efficient)

 s = size(a)[2] l(i,v) = i + v > s ? i + v - s : i + v map(i -> [a[i,i], a[i, l(i,1)], a[i, l(i,2)]], 1:5) 
+1
source share

Could you just define it yourself? How:

 a = repmat(collect(1:10)', 10) sza = size(a,1) #here 10 for i in 1:sza toget = collect(i:i+2) toget[toget.>sza] -= sza println(a[i, toget]) end [1,2,3] [2,3,4] [3,4,5] [4,5,6] [5,6,7] [6,7,8] [7,8,9] [8,9,10] [9,10,1] [10,1,2] 

Where can println be whatever you want?

+1
source share

All Articles