Array range padding

Is there a way to overwrite [] to complement the range in the array?

 julia> a=[1:8...] 8-element Array{Int64,1}: 1 2 3 4 5 6 7 8 julia> a[-1] == a[2:8] julia> a[-(1:3)] == a[4:8] julia> a[-end] == a[1:7] 
+6
source share
2 answers

I had not studied the insides of indexing before, but at first glance the following could work without interrupting too much:

 immutable Not{T} idx::T end if :to_indices in names(Base) # 0.6 import Base: to_indices, uncolon, tail, _maybetail @inline to_indices(A, inds, I::Tuple{Not, Vararg{Any}}) = (setdiff(uncolon(inds, (:, tail(I)...)), I[1].idx), to_indices(A, _maybetail(inds), tail(I))...) else # 0.5 import Base: getindex, _getindex not_index(a::AbstractArray, I, i::Int) = I not_index(a::AbstractArray, I::Not, i::Int) = setdiff(indices(a, i), I.idx) getindex(a::AbstractArray, I::Not) = getindex(a, setdiff(linearindices(a), I.idx)) _getindex(::Base.LinearIndexing, a::AbstractArray, I::Vararg{Union{Real, AbstractArray, Colon, Not}}) = Base._getindex(Base.linearindexing(a), a, (not_index(a, idx, i) for (i,idx) in enumerate(I))...) end 

For instance:

 julia> a = reshape(1:9, (3, 3)) 3×3 Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}: 1 4 7 2 5 8 3 6 9 julia> a[Not(2:8)] 2-element Array{Int64,1}: 1 9 julia> a[Not(1:2), :] 1×3 Array{Int64,2}: 3 6 9 julia> a[Not(end), end] 2-element Array{Int64,1}: 7 8 

I did not like the performance and extensive testing was not carried out, so everything can be improved.

Edit:

I replaced the code with 0.6 with version of Matt B. from his github comment linked in the comments.

Due to its excellent design of array indexing implementations for 0.6, only one function needs to be extended to get indexing additions for getindex , setindex and view , for example

 julia> view(a, Not(2:8)) 2-element SubArray{Int64,1,UnitRange{Int64},Tuple{Array{Int64,1}},false}: 1 9 # collect because ranges are immutable julia> b = collect(a); b[Not(2), Not(2)] = 10; b 3×3 Array{Int64,2}: 10 4 10 2 5 8 10 6 10 
+5
source

Direct rewriting of [] (i.e. getindex ) tends to break many things related to indexing in the database, but we can write an array wrapper to get around it. We need to define the following three methods to pass your specific test cases:

 immutable ComplementVector{T} <: AbstractArray{T,1} data::Vector{T} end Base.size(A:: ComplementVector) = size(A.data) Base.getindex(A:: ComplementVector, i::Integer) = i > 0 ? A.data[i] : A.data[setdiff(1:end, (-i))] Base.getindex(A:: ComplementVector, I::StepRange) = all(x->x>0, I) ? A.data[I] : A.data[setdiff(1:end, -I)] julia> a = ComplementVector([1:8...]) julia> a[-1] == a[2:8] true julia> a[-(1:3)] == a[4:8] true julia> a[-end] == a[1:7] true 

If you want to extend ComplementVector , please read the Interfaces document.

Update:

For security, we better not extend ExtArray, as suggested by @Fengyang Wang in a comment:

 immutable ComplementVector{T} data::Vector{T} end Base.endof(A::ComplementVector) = length(A.data) Base.getindex(A::ComplementVector, i::Integer) = i > 0 ? A.data[i] : A.data[setdiff(1:end, (-i))] Base.getindex(A::ComplementVector, I::OrdinalRange) = all(x->x>0, I) ? A.data[I] : A.data[setdiff(1:end, -I)] 
+4
source

Source: https://habr.com/ru/post/1015166/


All Articles