7
votes

I would like to slice an array a in Julia in a loop in such a way that it's divided in chunks of n samples. The length of the array nsamples is not a multiple of n, so the last stride would be shorter.

My attempt would be using a ternary operator to check if the size of the stride is greater than the length of the array:

for i in 0:n:nsamples-1
    end_ = i+n < nsamples ? i+n : end
    window = a[i+1:end_]
end

In this way, a[i+1:end_] would resolve to a[i+1:end] if I'm exceeding the size of the array.

However, the use of the keyword "end" in line 2 is not acceptable (it's also the keyword for "end of control statement" in julia.

In python, I can assign None to end_ and this would resolve to a[i+1:None], which will be the end of the array.

How can I get around this?

3

3 Answers

12
votes

The end keyword is only given this kind of special treatment inside of indexing expressions, where it evaluates to the last index of the dimension being indexed. You could put it inside with e.g.

for i in 0:n:nsamples-1
    window = a[i+1:min(i+n, end)]
end

Or you could just use length(a) (or nsamples, I guess they are the same?) instead of end to make it clear which end you are referring to.

2
votes

Ugly way:

a=rand(7);
nsamples=7;
n=3;
for i in 0:n:nsamples-1
    end_ = i+n < nsamples ? i+n : :end
    window = @eval a[$i+1:$end_]
    println(window)
end

Better solution:

for i in 0:n:nsamples-1
    window = i+n < nsamples ? a[i+1:i+n] : a[i+1:end]
    println(window)
end
1
votes

In order to simplify the loop (and perhaps improve performance) the last partial window can be processed after the loop. This is recommended since it usually requires some special processing anyway. In code:

i = 0 # define loop variable outside for to retain it after
for i=n:n:length(a)
    println(a[(i-n+1):i])
end
i < length(a) && println(a[(i+1):end])

The last bit can be done with an if but && is pretty clear.