# Convert AbstractVector to Vector

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)
``````

Will this always work, and be most efficient?

Easier to do `Vector(A)`, for example:

``````julia> Vector(1:3)
3-element Array{Int64,1}:
1
2
3
``````

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.

2 Likes

I prefer `A[:]` or `[A...]` (for an arbitrary iterable object).

`A[:]` won’t convert to a `Vector`, if `A` is a `UnitRange` for example, and the argument splatting in `[A...]` will be very inefficient for larger sizes.

3 Likes

`Vector(A)` doesn’t seem to work for OffsetArrays:

``````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`

These two things are not related at all — you can have two `AbstractVectors` with the same indices.

Incidentally, I would just check

``````axes(weights, 1) == axes(values, 1)
``````

to support generalized indexing.

Finally, you may be interested in

1 Like