For scientific applications, it is often useful to have arrays whose indices may start anywhere. Let's try to define a 1D array with this property, as an example of implementing a new type.
I want
a = IndexedArray([3,4,5], -7) # starting from -7
a[-7]
Exercise: What structure should it have?
type IndexedArray
data::Vector{Float64}
low_index::Integer
end
Exercise: Write a function that calculates the correct index.
We calculate the correct index once and for all:
reindex(a::IndexedArray, i) = i - a.low_index + 1
reindex (generic function with 1 method)
getindex(a::IndexedArray, i) = a.data[reindex(a, i)]
getindex (generic function with 182 methods)
v = IndexedArray([3, 4, 5], -3)
IndexedArray([3.0,4.0,5.0],-3)
v[-3]
3.0
v[-2]
4.0
v[-1]
5.0
v[0]
BoundsError() while loading In[7], in expression starting on line 1 in getindex at array.jl:246 in getindex at In[3]:1
v[-1] = 10
no method setindex!(IndexedArray, Int64, Int64) while loading In[8], in expression starting on line 1
Many operations already work:
v[-3:-2]
2-element Array{Float64,1}: 3.0 4.0
But others don't yet:
v[-3] = 10
no method setindex!(IndexedArray, Int64, Int64) while loading In[14], in expression starting on line 1
setindex!(a::IndexedArray, x, i) = a.data[reindex(a, i)] = x
setindex! (generic function with 115 methods)
v[-3] = 10
10
v
IndexedArray([10.0,4.0,5.0],-3)
v[-3] = 10
10
v
IndexedArray([10.0,4.0,5.0],-3)
for i in v
println(i)
end
no method start(IndexedArray) while loading In[13], in expression starting on line 1 in anonymous at no file
To define iteration for our new type, we need to define the start
, next
and done
functions.
To see how to do so, the easiest thing is to copy some pre-existing code!
methods(start)
Let's pick the one for an abstract array. This is what we need to implement:
# start(a::AbstractArray) = 1
# next(a::AbstractArray,i) = (a[i],i+1)
# done(a::AbstractArray,i) = (i > length(a))
First, we must, as the error message says, explicitly import the functions from Base
in order to extend them:
import Base: start, next, done
Warning: import of Base.start into Main conflicts with an existing identifier; ignored. Warning: import of Base.next into Main conflicts with an existing identifier; ignored. Warning: import of Base.done into Main conflicts with an existing identifier; ignored.
start(a::IndexedArray) = a.low_index
next(a::IndexedArray,i) = (a[i],i+1)
done(a::IndexedArray,i) = (i > a.low_index + length(a) - 1)
done (generic function with 1 method)
v
IndexedArray([10.0,4.0,5.0],-3)
for i in v
println(i)
end
no method start(IndexedArray) while loading In[24], in expression starting on line 1 in anonymous at no file
length(a::IndexedArray) = length(a.data)
length (generic function with 1 method)
import Base.length
length(a::IndexedArray) = length(a.data)
length (generic function with 58 methods)
for i in v
println(i)
end
10.0 4.0 5.0
v
IndexedArray([10.0,4.0,5.0],-3)
v + v
no method +(IndexedArray, IndexedArray) while loading In[27], in expression starting on line 1