2016-09-29 1 views
7

У меня есть простой вопрос, который должен иметь простой ответ, но я пока не могу придумать его. Я хочу обрабатывать массив, определенное количество элементов за раз и обертывать до начала.Доступ к массиву некоторых элементов за один раз и обертывание до начала

Вот диаграмма, показывающая, когда n 10 и три элемента хотелось каждый раз:

iterations 3 at a time

Мои попытки написать простой итерации до сих пор не увенчались успехом: с помощью % n дает мне нули, которые дон» т работа с одной индексации Джулии ... :)

+0

Nice diagram. Обычно перед выполнением '% n' вам нужно вычесть 1, а затем добавить 1 (напоминающий матричное преобразование матрицы в линейной алгебре). Кроме того, есть пакеты, которые позволяют индексировать массивы на основе 0 (и других), см. OffsetArrays (https://github.com/alsam/OffsetArrays.jl). –

ответ

10

mod1 функция предусмотрена, чтобы поведение вы хотите:

julia> mod1(1, 5) 
1 

julia> mod1(3, 5) 
3 

julia> mod1(5, 5) 
5 

julia> mod1(6, 5) 
1 

Это довольно просто сделать моды индексированной функции:

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

Или даже ваш собственных модами индексированного типа массива :

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 

Непросто реализовать нарезку сверху это. Как DNF упоминалось в комментариях, чистое и лаконичное решение

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

или эквивалент getindex, который обрабатывает как скалярную индексацию и нарезку.


Edit: Так как ваш вопрос упоминается итерация, я полагаю, я бы обеспечить более общее решение, которое также работает на не-массивах для целей итерации, используя только функциональную итерируемые в 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

Чистым решением может быть «modindex (A, i) = A [mod1. (I, end)]». Это очень сложно, и вы можете делать нарезку. – DNF

+0

Отличный ответ, только то, что мне нужно. Благодарю. – daycaster

+0

В определении 'CircArray' не следует, чтобы' T' в суперклассе заменялся параметром 'T'? (или параметр, реорганизованный как 'eltype' массива, с дополнительным модификатором' Vector' на 'xs') –

1

Для

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

сделать

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 

, а затем

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

Если вы хотите над инженером этого, или память является проблемой (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

Вы могли бы просто определить это самостоятельно? Как:

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] 

Где println может быть все, что вы хотите?

+0

Спасибо, хорошо знаю, как это можно сделать. – daycaster

4

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) 

и как 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] 
+1

Вы также можете использовать «цикл» на итераторе, а затем «взять результат». Я включил подобное решение в свой ответ. –

+0

Хороший ответ, спасибо. – daycaster