2016-09-29 43 views
7

Mam proste pytanie, które powinno dać prostą odpowiedź, ale nie mogę jeszcze o tym myśleć. Chcę przetworzyć tablicę, pewną liczbę elementów naraz i owijać ją od początku do początku.Uzyskiwanie dostępu do tablicy niektórych elementów naraz i zawijanie do początku

Oto pokazano schemat kiedy n wynosi 10, a trzy elementy są chciał za każdym razem:

iterations 3 at a time

Moje próby napisać prosty iteracji dotąd nie powiodło się: korzystania % n daje mi zer, które don” t praca z jednej indeksowania Julii ... :)

+0

Ładny schemat. Zwykle przed wykonaniem '% n' należy odjąć 1, a następnie dodać 1 (przypominające transformację bazy w algebrze liniowej). Istnieją również pakiety, które umożliwiają indeksowanie tablic w oparciu o 0 (i inne), zobacz OffsetArrays (https://github.com/alsam/OffsetArrays.jl). –

Odpowiedz

10

Funkcja mod1 jest, aby umożliwić zachowanie pragnienie:

julia> mod1(1, 5) 
1 

julia> mod1(3, 5) 
3 

julia> mod1(5, 5) 
5 

julia> mod1(6, 5) 
1 

Jest to dość proste, aby mod indeksowane funkcję:

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

Albo nawet swój własny mod indeksowane typu array :

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 

Nie jest to zbyt trudne do wykonania krojenia na wierzchu to. Jak wspomniano DNF w komentarzu czyste i zwięzły roztwór

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

lub odpowiednika getindex, który obsługuje obydwie skalarne indeksowania i krojenia.


Edit: Ponieważ Twoje pytanie wspomniano iteracji, ja figura ja zapewniają bardziej ogólne rozwiązanie, które działa również na innych niż dla celów macierzy iteracji, przy użyciu tylko iterables funkcjonalnych 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

Czystym rozwiązaniem może być 'modindex (A, i) = A [mod1. (I, end)]'. Jest super zwięzły i możesz robić krojenie. – DNF

+0

Świetna odpowiedź, właśnie to, czego potrzebowałem. Dzięki. – daycaster

+0

W definicji 'CircArray' nie należy zastąpić' T' w superklasie przez parametr 'T'? (lub parametr refaktoryzowany na 'eltype' tablicy, z dodatkowym modyfikatorem' Vector' na 'xs') –

1

Dla

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

zrobić

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 

a następnie

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

Jeśli chcesz na inżyniera tego, czy pamięć jest problem (repmat nie jest dokładnie pamięć wydajny)

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

Można go zdefiniować samodzielnie? Podobnych:

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] 

Gdzie println może być cokolwiek chcesz?

+0

Dzięki, dobrze wiedzieć, jak można to zrobić. – daycaster

4

Iterators.jl daje prosty iterator do „dostępie do tablicy kilka elementów na raz”:

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) 

i jak zasugerował Feng Yang Wang, funkcja mod1 wykonuje "zawijanie do początku". po prostu wykonaj kombinację:

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

Możesz również rozważyć użycie 'cycle' na iteratorze, a następnie' take'ing wyniku. Włączyłem podobne rozwiązanie do mojej odpowiedzi. –

+0

Dobra odpowiedź, dzięki. – daycaster