一次访问一些数组并循环到开头

时间:2022-05-06 16:48:25

I have a simple question that should have a simple answer but I can't think of it yet. I want to process an array, a certain number of elements at a time, and wrapping round to the beginning.

我有一个简单的问题应该有一个简单的答案,但我还没想到它。我想一次处理一个数组,一定数量的元素,然后回绕到开头。

Here's a diagram showing when n is 10 and three elements are wanted each time:

这是一个图表,显示当n为10时,每次需要三个元素:

一次访问一些数组并循环到开头

My attempts to write a simple iteration so far have failed: using % n gives me zeros, which don't work with Julia's one-indexing... :)

到目前为止,我尝试编写一个简单的迭代失败了:使用%n给我零,这不适用于Julia的一个索引...... :)

4 个解决方案

#1


10  

The mod1 function is provided to allow the behaviour you desire:

提供mod1函数以允许您需要的行为:

julia> mod1(1, 5)
1

julia> mod1(3, 5)
3

julia> mod1(5, 5)
5

julia> mod1(6, 5)
1

It's pretty straightforward to make a mod-indexed function:

制作mod-indexed函数非常简单:

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

Or even your own mod-indexed array type:

甚至你自己的mod索引数组类型:

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 mentioned in a comment, a clean and concise solution is

在此基础上实现切片并不太难。正如DNF在评论中提到的那样,一个简洁明了的解决方案就是

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

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

或getindex的等价物,它处理标量索引和切片。


Edit: Since your question mentioned iteration, I figure I'd provide a more general solution that also works on non-arrays for iteration purposes, using only the functional iterables in Base:

编辑:由于你的问题提到迭代,我想我会提供一个更通用的解决方案,也可以在非数组上用于迭代目的,只使用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

#2


4  

Iterators.jl will give you the simple iterator to "accessing an array some elements at a time":

Iterators.jl将为您提供“一次访问数组一些元素”的简单迭代器:

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 mod1 function does the "wrapping round to the beginning" job. just make a combination:

正如FengYang Wang所说,mod1函数执行“包装到开头”工作。只是组合:

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]

#3


1  

You could just define it yourself? Like:

你可以自己定义一下吗?喜欢:

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 println could be whatever you want?

println可以是你想要的任何东西吗?

#4


1  

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 wanna over engineer this, or memory is an issue (repmat is not exactly memory efficient)

如果你想过度设计这个,或者内存是一个问题(repmat并不完全是内存效率)

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


10  

The mod1 function is provided to allow the behaviour you desire:

提供mod1函数以允许您需要的行为:

julia> mod1(1, 5)
1

julia> mod1(3, 5)
3

julia> mod1(5, 5)
5

julia> mod1(6, 5)
1

It's pretty straightforward to make a mod-indexed function:

制作mod-indexed函数非常简单:

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

Or even your own mod-indexed array type:

甚至你自己的mod索引数组类型:

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 mentioned in a comment, a clean and concise solution is

在此基础上实现切片并不太难。正如DNF在评论中提到的那样,一个简洁明了的解决方案就是

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

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

或getindex的等价物,它处理标量索引和切片。


Edit: Since your question mentioned iteration, I figure I'd provide a more general solution that also works on non-arrays for iteration purposes, using only the functional iterables in Base:

编辑:由于你的问题提到迭代,我想我会提供一个更通用的解决方案,也可以在非数组上用于迭代目的,只使用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

#2


4  

Iterators.jl will give you the simple iterator to "accessing an array some elements at a time":

Iterators.jl将为您提供“一次访问数组一些元素”的简单迭代器:

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 mod1 function does the "wrapping round to the beginning" job. just make a combination:

正如FengYang Wang所说,mod1函数执行“包装到开头”工作。只是组合:

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]

#3


1  

You could just define it yourself? Like:

你可以自己定义一下吗?喜欢:

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 println could be whatever you want?

println可以是你想要的任何东西吗?

#4


1  

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 wanna over engineer this, or memory is an issue (repmat is not exactly memory efficient)

如果你想过度设计这个,或者内存是一个问题(repmat并不完全是内存效率)

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)