What is a generic, idiomatic and performant method to convert an AbstractVector (which may have non-standard indexing) to a Vector?
I want to treat the AbstractVector as list of items to be “loaded” into a regular Vector.
MyConvert(A::AbstractArray{T}) where {T} = copy!(Vector{T}(undef, length(A)), A)
But in general I would urge you to avoid this conversion if you can — a different array type could easily be more efficient than a Vector for various specialized cases. For example, a range like 1:10^7 requires vastly less memory than a corresponding Vector. It is better to write generic code that works with any array type. The compiler will specialize your code for you on the actual argument type that is passed.
Julia-1.2.0> using OffsetArrays
Julia-1.2.0> A = OffsetVector([1,2,3], -1:1)
3-element OffsetArray(::Array{Int64,1}, -1:1) with eltype Int64 with indices -1:1:
1
2
3
Julia-1.2.0> Vector(A)
ERROR: BoundsError: attempt to access 3-element Array{Int64,1} at index [Base.IdentityUnitRange(-1:1)]
Stacktrace:
[1] throw_boundserror(::Array{Int64,1}, ::Tuple{Base.IdentityUnitRange{UnitRange{Int64}}}) at .\abstractarray.jl:538
[2] checkbounds at .\abstractarray.jl:503 [inlined]
[3] copyto!(::Array{Int64,1}, ::OffsetArray{Int64,1,Array{Int64,1}}) at .\multidimensional.jl:902
[4] Array{T,1} where T(::OffsetArray{Int64,1,Array{Int64,1}}) at .\array.jl:482
[5] top-level scope at REPL[7]:1
whereas explicit copy to Vector does seem work:
Julia-1.2.0> copy!(Vector{Int}(undef, length(A)), A)
3-element Array{Int64,1}:
1
2
3
Yes, this is a good point. I might have to rethink my implementation.
My usecase is for a “WeightedVector”, which returns values base on weights. In this case, it seemed appropriate for values to also be a Vector to match weights, so that the indices are the same (when weight[i] is selected, return value[i]).
struct WeightVector{W<:Real,V}
weights::Vector{W}
values::Vector{V}
sumWeights::W
function WeightVector{W,V}(weights::Vector{W}, values::Vector{V}) where {W<:Real,V}
length(weights) == length(values) || throw(ArgumentError("length of weights and values vectors must be equal"))
issorted(weights, rev=true) || throw(ArgumentError("weights must be sorted in descending order"))
return new(weights, values, sum(weights))
end
end
I could perhaps change values::Vector{V} ----> values::A where A<:AbstractVector