2015 lines
45 KiB
Julia
2015 lines
45 KiB
Julia
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||
|
||
## array.jl: Dense arrays
|
||
|
||
## Type aliases for convenience ##
|
||
|
||
const AbstractVector{T} = AbstractArray{T,1}
|
||
const AbstractMatrix{T} = AbstractArray{T,2}
|
||
const AbstractVecOrMat{T} = Union{AbstractVector{T}, AbstractMatrix{T}}
|
||
const RangeIndex = Union{Int, Range{Int}, AbstractUnitRange{Int}}
|
||
const DimOrInd = Union{Integer, AbstractUnitRange}
|
||
const IntOrInd = Union{Int, AbstractUnitRange}
|
||
const DimsOrInds{N} = NTuple{N,DimOrInd}
|
||
const NeedsShaping = Union{Tuple{Integer,Vararg{Integer}}, Tuple{OneTo,Vararg{OneTo}}}
|
||
|
||
const Vector{T} = Array{T,1}
|
||
const Matrix{T} = Array{T,2}
|
||
const VecOrMat{T} = Union{Vector{T}, Matrix{T}}
|
||
|
||
const DenseVector{T} = DenseArray{T,1}
|
||
const DenseMatrix{T} = DenseArray{T,2}
|
||
const DenseVecOrMat{T} = Union{DenseVector{T}, DenseMatrix{T}}
|
||
|
||
## Basic functions ##
|
||
|
||
"""
|
||
eltype(type)
|
||
|
||
Determine the type of the elements generated by iterating a collection of the given `type`.
|
||
For associative collection types, this will be a `Pair{KeyType,ValType}`. The definition
|
||
`eltype(x) = eltype(typeof(x))` is provided for convenience so that instances can be passed
|
||
instead of types. However the form that accepts a type argument should be defined for new
|
||
types.
|
||
|
||
```jldoctest
|
||
julia> eltype(ones(Float32,2,2))
|
||
Float32
|
||
|
||
julia> eltype(ones(Int8,2,2))
|
||
Int8
|
||
```
|
||
"""
|
||
eltype(::Type) = Any
|
||
eltype(::Type{Any}) = Any
|
||
eltype(::Type{Bottom}) = throw(ArgumentError("Union{} does not have elements"))
|
||
eltype(t::DataType) = eltype(supertype(t))
|
||
eltype(x) = eltype(typeof(x))
|
||
|
||
import Core: arraysize, arrayset, arrayref
|
||
|
||
"""
|
||
Array{T}(dims)
|
||
Array{T,N}(dims)
|
||
|
||
Construct an uninitialized `N`-dimensional dense array with element type `T`,
|
||
where `N` is determined from the length or number of `dims`. `dims` may
|
||
be a tuple or a series of integer arguments corresponding to the lengths in each dimension.
|
||
If the rank `N` is supplied explicitly as in `Array{T,N}(dims)`, then it must
|
||
match the length or number of `dims`.
|
||
|
||
# Example
|
||
|
||
```jldoctest
|
||
julia> A = Array{Float64, 2}(2, 2);
|
||
|
||
julia> ndims(A)
|
||
2
|
||
|
||
julia> eltype(A)
|
||
Float64
|
||
```
|
||
"""
|
||
Array
|
||
|
||
vect() = Array{Any,1}(0)
|
||
vect(X::T...) where {T} = T[ X[i] for i = 1:length(X) ]
|
||
|
||
function vect(X...)
|
||
T = promote_typeof(X...)
|
||
#T[ X[i] for i=1:length(X) ]
|
||
# TODO: this is currently much faster. should figure out why. not clear.
|
||
return copy!(Array{T,1}(length(X)), X)
|
||
end
|
||
|
||
size(a::Array, d) = arraysize(a, d)
|
||
size(a::Vector) = (arraysize(a,1),)
|
||
size(a::Matrix) = (arraysize(a,1), arraysize(a,2))
|
||
size(a::Array{<:Any,N}) where {N} = (@_inline_meta; ntuple(M -> size(a, M), Val{N}))
|
||
|
||
asize_from(a::Array, n) = n > ndims(a) ? () : (arraysize(a,n), asize_from(a, n+1)...)
|
||
|
||
length(a::Array) = arraylen(a)
|
||
elsize(a::Array{T}) where {T} = isbits(T) ? sizeof(T) : sizeof(Ptr)
|
||
sizeof(a::Array) = elsize(a) * length(a)
|
||
|
||
function isassigned(a::Array, i::Int...)
|
||
@_inline_meta
|
||
ii = (sub2ind(size(a), i...) % UInt) - 1
|
||
ii < length(a) % UInt || return false
|
||
ccall(:jl_array_isassigned, Cint, (Any, UInt), a, ii) == 1
|
||
end
|
||
|
||
## copy ##
|
||
|
||
function unsafe_copy!(dest::Ptr{T}, src::Ptr{T}, n) where T
|
||
# Do not use this to copy data between pointer arrays.
|
||
# It can't be made safe no matter how carefully you checked.
|
||
ccall(:memmove, Ptr{Void}, (Ptr{Void}, Ptr{Void}, UInt),
|
||
dest, src, n*sizeof(T))
|
||
return dest
|
||
end
|
||
|
||
function unsafe_copy!(dest::Array{T}, doffs, src::Array{T}, soffs, n) where T
|
||
if isbits(T)
|
||
unsafe_copy!(pointer(dest, doffs), pointer(src, soffs), n)
|
||
else
|
||
ccall(:jl_array_ptr_copy, Void, (Any, Ptr{Void}, Any, Ptr{Void}, Int),
|
||
dest, pointer(dest, doffs), src, pointer(src, soffs), n)
|
||
end
|
||
return dest
|
||
end
|
||
|
||
function copy!(dest::Array{T}, doffs::Integer, src::Array{T}, soffs::Integer, n::Integer) where T
|
||
n == 0 && return dest
|
||
n > 0 || throw(ArgumentError(string("tried to copy n=", n, " elements, but n should be nonnegative")))
|
||
if soffs < 1 || doffs < 1 || soffs+n-1 > length(src) || doffs+n-1 > length(dest)
|
||
throw(BoundsError())
|
||
end
|
||
unsafe_copy!(dest, doffs, src, soffs, n)
|
||
end
|
||
|
||
copy!(dest::Array{T}, src::Array{T}) where {T} = copy!(dest, 1, src, 1, length(src))
|
||
|
||
copy(a::T) where {T<:Array} = ccall(:jl_array_copy, Ref{T}, (Any,), a)
|
||
|
||
function reinterpret(::Type{T}, a::Array{S,1}) where T where S
|
||
nel = Int(div(length(a)*sizeof(S),sizeof(T)))
|
||
# TODO: maybe check that remainder is zero?
|
||
return reinterpret(T, a, (nel,))
|
||
end
|
||
|
||
function reinterpret(::Type{T}, a::Array{S}) where T where S
|
||
if sizeof(S) != sizeof(T)
|
||
throw(ArgumentError("result shape not specified"))
|
||
end
|
||
reinterpret(T, a, size(a))
|
||
end
|
||
|
||
function reinterpret(::Type{T}, a::Array{S}, dims::NTuple{N,Int}) where T where S where N
|
||
if !isbits(T)
|
||
throw(ArgumentError("cannot reinterpret Array{$(S)} to ::Type{Array{$(T)}}, type $(T) is not a bits type"))
|
||
end
|
||
if !isbits(S)
|
||
throw(ArgumentError("cannot reinterpret Array{$(S)} to ::Type{Array{$(T)}}, type $(S) is not a bits type"))
|
||
end
|
||
nel = div(length(a)*sizeof(S),sizeof(T))
|
||
if prod(dims) != nel
|
||
throw(DimensionMismatch("new dimensions $(dims) must be consistent with array size $(nel)"))
|
||
end
|
||
ccall(:jl_reshape_array, Array{T,N}, (Any, Any, Any), Array{T,N}, a, dims)
|
||
end
|
||
|
||
# reshaping to same # of dimensions
|
||
function reshape(a::Array{T,N}, dims::NTuple{N,Int}) where T where N
|
||
if prod(dims) != length(a)
|
||
throw(DimensionMismatch("new dimensions $(dims) must be consistent with array size $(length(a))"))
|
||
end
|
||
if dims == size(a)
|
||
return a
|
||
end
|
||
ccall(:jl_reshape_array, Array{T,N}, (Any, Any, Any), Array{T,N}, a, dims)
|
||
end
|
||
|
||
# reshaping to different # of dimensions
|
||
function reshape(a::Array{T}, dims::NTuple{N,Int}) where T where N
|
||
if prod(dims) != length(a)
|
||
throw(DimensionMismatch("new dimensions $(dims) must be consistent with array size $(length(a))"))
|
||
end
|
||
ccall(:jl_reshape_array, Array{T,N}, (Any, Any, Any), Array{T,N}, a, dims)
|
||
end
|
||
|
||
## Constructors ##
|
||
|
||
similar(a::Array{T,1}) where {T} = Array{T,1}(size(a,1))
|
||
similar(a::Array{T,2}) where {T} = Array{T,2}(size(a,1), size(a,2))
|
||
similar(a::Array{T,1}, S::Type) where {T} = Array{S,1}(size(a,1))
|
||
similar(a::Array{T,2}, S::Type) where {T} = Array{S,2}(size(a,1), size(a,2))
|
||
similar(a::Array{T}, m::Int) where {T} = Array{T,1}(m)
|
||
similar(a::Array, T::Type, dims::Dims{N}) where {N} = Array{T,N}(dims)
|
||
similar(a::Array{T}, dims::Dims{N}) where {T,N} = Array{T,N}(dims)
|
||
|
||
# T[x...] constructs Array{T,1}
|
||
function getindex(::Type{T}, vals...) where T
|
||
a = Array{T,1}(length(vals))
|
||
@inbounds for i = 1:length(vals)
|
||
a[i] = vals[i]
|
||
end
|
||
return a
|
||
end
|
||
|
||
getindex(::Type{T}) where {T} = (@_inline_meta; Array{T,1}(0))
|
||
getindex(::Type{T}, x) where {T} = (@_inline_meta; a = Array{T,1}(1); @inbounds a[1] = x; a)
|
||
getindex(::Type{T}, x, y) where {T} = (@_inline_meta; a = Array{T,1}(2); @inbounds (a[1] = x; a[2] = y); a)
|
||
getindex(::Type{T}, x, y, z) where {T} = (@_inline_meta; a = Array{T,1}(3); @inbounds (a[1] = x; a[2] = y; a[3] = z); a)
|
||
|
||
function getindex(::Type{Any}, vals::ANY...)
|
||
a = Array{Any,1}(length(vals))
|
||
@inbounds for i = 1:length(vals)
|
||
a[i] = vals[i]
|
||
end
|
||
return a
|
||
end
|
||
getindex(::Type{Any}) = Array{Any,1}(0)
|
||
|
||
function fill!(a::Union{Array{UInt8}, Array{Int8}}, x::Integer)
|
||
ccall(:memset, Ptr{Void}, (Ptr{Void}, Cint, Csize_t), a, x, length(a))
|
||
return a
|
||
end
|
||
|
||
function fill!(a::Array{T}, x) where T<:Union{Integer,AbstractFloat}
|
||
xT = convert(T, x)
|
||
for i in eachindex(a)
|
||
@inbounds a[i] = xT
|
||
end
|
||
return a
|
||
end
|
||
|
||
|
||
"""
|
||
fill(x, dims)
|
||
|
||
Create an array filled with the value `x`. For example, `fill(1.0, (5,5))` returns a 5×5
|
||
array of floats, with each element initialized to `1.0`.
|
||
|
||
```jldoctest
|
||
julia> fill(1.0, (5,5))
|
||
5×5 Array{Float64,2}:
|
||
1.0 1.0 1.0 1.0 1.0
|
||
1.0 1.0 1.0 1.0 1.0
|
||
1.0 1.0 1.0 1.0 1.0
|
||
1.0 1.0 1.0 1.0 1.0
|
||
1.0 1.0 1.0 1.0 1.0
|
||
```
|
||
|
||
If `x` is an object reference, all elements will refer to the same object. `fill(Foo(),
|
||
dims)` will return an array filled with the result of evaluating `Foo()` once.
|
||
"""
|
||
fill(v, dims::Dims) = fill!(Array{typeof(v)}(dims), v)
|
||
fill(v, dims::Integer...) = fill!(Array{typeof(v)}(dims...), v)
|
||
|
||
for (fname, felt) in ((:zeros,:zero), (:ones,:one))
|
||
@eval begin
|
||
# allow signature of similar
|
||
$fname(a::AbstractArray, T::Type, dims::Tuple) = fill!(similar(a, T, dims), $felt(T))
|
||
$fname(a::AbstractArray, T::Type, dims...) = fill!(similar(a,T,dims...), $felt(T))
|
||
$fname(a::AbstractArray, T::Type=eltype(a)) = fill!(similar(a,T), $felt(T))
|
||
|
||
$fname(T::Type, dims::Tuple) = fill!(Array{T}(Dims(dims)), $felt(T))
|
||
$fname(dims::Tuple) = ($fname)(Float64, dims)
|
||
$fname(T::Type, dims...) = $fname(T, dims)
|
||
$fname(dims...) = $fname(dims)
|
||
end
|
||
end
|
||
|
||
"""
|
||
eye([T::Type=Float64,] m::Integer, n::Integer)
|
||
|
||
`m`-by-`n` identity matrix.
|
||
The default element type is [`Float64`](@ref).
|
||
|
||
# Examples
|
||
|
||
```jldoctest
|
||
julia> eye(3, 4)
|
||
3×4 Array{Float64,2}:
|
||
1.0 0.0 0.0 0.0
|
||
0.0 1.0 0.0 0.0
|
||
0.0 0.0 1.0 0.0
|
||
|
||
julia> eye(2, 2)
|
||
2×2 Array{Float64,2}:
|
||
1.0 0.0
|
||
0.0 1.0
|
||
|
||
julia> eye(Int, 2, 2)
|
||
2×2 Array{Int64,2}:
|
||
1 0
|
||
0 1
|
||
```
|
||
"""
|
||
function eye(::Type{T}, m::Integer, n::Integer) where T
|
||
a = zeros(T,m,n)
|
||
for i = 1:min(m,n)
|
||
a[i,i] = oneunit(T)
|
||
end
|
||
return a
|
||
end
|
||
|
||
"""
|
||
eye(m, n)
|
||
|
||
`m`-by-`n` identity matrix.
|
||
"""
|
||
eye(m::Integer, n::Integer) = eye(Float64, m, n)
|
||
eye(::Type{T}, n::Integer) where {T} = eye(T, n, n)
|
||
"""
|
||
eye([T::Type=Float64,] n::Integer)
|
||
|
||
`n`-by-`n` identity matrix.
|
||
The default element type is [`Float64`](@ref).
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> eye(Int, 2)
|
||
2×2 Array{Int64,2}:
|
||
1 0
|
||
0 1
|
||
|
||
julia> eye(2)
|
||
2×2 Array{Float64,2}:
|
||
1.0 0.0
|
||
0.0 1.0
|
||
```
|
||
"""
|
||
eye(n::Integer) = eye(Float64, n)
|
||
|
||
"""
|
||
eye(A)
|
||
|
||
Constructs an identity matrix of the same dimensions and type as `A`.
|
||
|
||
```jldoctest
|
||
julia> A = [1 2 3; 4 5 6; 7 8 9]
|
||
3×3 Array{Int64,2}:
|
||
1 2 3
|
||
4 5 6
|
||
7 8 9
|
||
|
||
julia> eye(A)
|
||
3×3 Array{Int64,2}:
|
||
1 0 0
|
||
0 1 0
|
||
0 0 1
|
||
```
|
||
|
||
Note the difference from [`ones`](@ref).
|
||
"""
|
||
eye(x::AbstractMatrix{T}) where {T} = eye(typeof(one(T)), size(x, 1), size(x, 2))
|
||
|
||
function _one(unit::T, x::AbstractMatrix) where T
|
||
m,n = size(x)
|
||
m==n || throw(DimensionMismatch("multiplicative identity defined only for square matrices"))
|
||
eye(T, m)
|
||
end
|
||
|
||
one(x::AbstractMatrix{T}) where {T} = _one(one(T), x)
|
||
oneunit(x::AbstractMatrix{T}) where {T} = _one(oneunit(T), x)
|
||
|
||
## Conversions ##
|
||
|
||
convert(::Type{Vector}, x::AbstractVector{T}) where {T} = convert(Vector{T}, x)
|
||
convert(::Type{Matrix}, x::AbstractMatrix{T}) where {T} = convert(Matrix{T}, x)
|
||
|
||
convert(::Type{Array{T}}, x::Array{T,n}) where {T,n} = x
|
||
convert(::Type{Array{T,n}}, x::Array{T,n}) where {T,n} = x
|
||
|
||
convert(::Type{Array{T}}, x::AbstractArray{S,n}) where {T,n,S} = convert(Array{T,n}, x)
|
||
convert(::Type{Array{T,n}}, x::AbstractArray{S,n}) where {T,n,S} = copy!(Array{T,n}(size(x)), x)
|
||
|
||
promote_rule(::Type{Array{T,n}}, ::Type{Array{S,n}}) where {T,n,S} = Array{promote_type(T,S),n}
|
||
|
||
## copying iterators to containers
|
||
|
||
"""
|
||
collect(element_type, collection)
|
||
|
||
Return an `Array` with the given element type of all items in a collection or iterable.
|
||
The result has the same shape and number of dimensions as `collection`.
|
||
|
||
```jldoctest
|
||
julia> collect(Float64, 1:2:5)
|
||
3-element Array{Float64,1}:
|
||
1.0
|
||
3.0
|
||
5.0
|
||
```
|
||
"""
|
||
collect(::Type{T}, itr) where {T} = _collect(T, itr, iteratorsize(itr))
|
||
|
||
_collect(::Type{T}, itr, isz::HasLength) where {T} = copy!(Array{T,1}(Int(length(itr)::Integer)), itr)
|
||
_collect(::Type{T}, itr, isz::HasShape) where {T} = copy!(similar(Array{T}, indices(itr)), itr)
|
||
function _collect(::Type{T}, itr, isz::SizeUnknown) where T
|
||
a = Array{T,1}(0)
|
||
for x in itr
|
||
push!(a,x)
|
||
end
|
||
return a
|
||
end
|
||
|
||
# make a collection similar to `c` and appropriate for collecting `itr`
|
||
_similar_for(c::AbstractArray, T, itr, ::SizeUnknown) = similar(c, T, 0)
|
||
_similar_for(c::AbstractArray, T, itr, ::HasLength) = similar(c, T, Int(length(itr)::Integer))
|
||
_similar_for(c::AbstractArray, T, itr, ::HasShape) = similar(c, T, indices(itr))
|
||
_similar_for(c, T, itr, isz) = similar(c, T)
|
||
|
||
"""
|
||
collect(collection)
|
||
|
||
Return an `Array` of all items in a collection or iterator. For associative collections, returns
|
||
`Pair{KeyType, ValType}`. If the argument is array-like or is an iterator with the `HasShape()`
|
||
trait, the result will have the same shape and number of dimensions as the argument.
|
||
|
||
# Example
|
||
```jldoctest
|
||
julia> collect(1:2:13)
|
||
7-element Array{Int64,1}:
|
||
1
|
||
3
|
||
5
|
||
7
|
||
9
|
||
11
|
||
13
|
||
```
|
||
"""
|
||
collect(itr) = _collect(1:1 #= Array =#, itr, iteratoreltype(itr), iteratorsize(itr))
|
||
|
||
collect(A::AbstractArray) = _collect_indices(indices(A), A)
|
||
|
||
collect_similar(cont, itr) = _collect(cont, itr, iteratoreltype(itr), iteratorsize(itr))
|
||
|
||
_collect(cont, itr, ::HasEltype, isz::Union{HasLength,HasShape}) =
|
||
copy!(_similar_for(cont, eltype(itr), itr, isz), itr)
|
||
|
||
function _collect(cont, itr, ::HasEltype, isz::SizeUnknown)
|
||
a = _similar_for(cont, eltype(itr), itr, isz)
|
||
for x in itr
|
||
push!(a,x)
|
||
end
|
||
return a
|
||
end
|
||
|
||
_collect_indices(::Tuple{}, A) = copy!(Array{eltype(A)}(), A)
|
||
_collect_indices(indsA::Tuple{Vararg{OneTo}}, A) =
|
||
copy!(Array{eltype(A)}(length.(indsA)), A)
|
||
function _collect_indices(indsA, A)
|
||
B = Array{eltype(A)}(length.(indsA))
|
||
copy!(B, CartesianRange(indices(B)), A, CartesianRange(indsA))
|
||
end
|
||
|
||
if isdefined(Core, :Inference)
|
||
_default_eltype(itrt::ANY) = Core.Inference.return_type(first, Tuple{itrt})
|
||
else
|
||
_default_eltype(itr::ANY) = Any
|
||
end
|
||
|
||
_array_for(::Type{T}, itr, ::HasLength) where {T} = Array{T,1}(Int(length(itr)::Integer))
|
||
_array_for(::Type{T}, itr, ::HasShape) where {T} = similar(Array{T}, indices(itr))
|
||
|
||
function collect(itr::Generator)
|
||
isz = iteratorsize(itr.iter)
|
||
et = _default_eltype(typeof(itr))
|
||
if isa(isz, SizeUnknown)
|
||
return grow_to!(Array{et,1}(0), itr)
|
||
else
|
||
st = start(itr)
|
||
if done(itr,st)
|
||
return _array_for(et, itr.iter, isz)
|
||
end
|
||
v1, st = next(itr, st)
|
||
collect_to_with_first!(_array_for(typeof(v1), itr.iter, isz), v1, itr, st)
|
||
end
|
||
end
|
||
|
||
_collect(c, itr, ::EltypeUnknown, isz::SizeUnknown) =
|
||
grow_to!(_similar_for(c, _default_eltype(typeof(itr)), itr, isz), itr)
|
||
|
||
function _collect(c, itr, ::EltypeUnknown, isz::Union{HasLength,HasShape})
|
||
st = start(itr)
|
||
if done(itr,st)
|
||
return _similar_for(c, _default_eltype(typeof(itr)), itr, isz)
|
||
end
|
||
v1, st = next(itr, st)
|
||
collect_to_with_first!(_similar_for(c, typeof(v1), itr, isz), v1, itr, st)
|
||
end
|
||
|
||
function collect_to_with_first!(dest::AbstractArray, v1, itr, st)
|
||
i1 = first(linearindices(dest))
|
||
dest[i1] = v1
|
||
return collect_to!(dest, itr, i1+1, st)
|
||
end
|
||
|
||
function collect_to_with_first!(dest, v1, itr, st)
|
||
push!(dest, v1)
|
||
return grow_to!(dest, itr, st)
|
||
end
|
||
|
||
function collect_to!(dest::AbstractArray{T}, itr, offs, st) where T
|
||
# collect to dest array, checking the type of each result. if a result does not
|
||
# match, widen the result type and re-dispatch.
|
||
i = offs
|
||
while !done(itr, st)
|
||
el, st = next(itr, st)
|
||
S = typeof(el)
|
||
if S === T || S <: T
|
||
@inbounds dest[i] = el::T
|
||
i += 1
|
||
else
|
||
R = typejoin(T, S)
|
||
new = similar(dest, R)
|
||
copy!(new,1, dest,1, i-1)
|
||
@inbounds new[i] = el
|
||
return collect_to!(new, itr, i+1, st)
|
||
end
|
||
end
|
||
return dest
|
||
end
|
||
|
||
function grow_to!(dest, itr)
|
||
out = grow_to!(similar(dest,Union{}), itr, start(itr))
|
||
return isempty(out) ? dest : out
|
||
end
|
||
|
||
function grow_to!(dest, itr, st)
|
||
T = eltype(dest)
|
||
while !done(itr, st)
|
||
el, st = next(itr, st)
|
||
S = typeof(el)
|
||
if S === T || S <: T
|
||
push!(dest, el::T)
|
||
else
|
||
new = similar(dest, typejoin(T, S))
|
||
copy!(new, dest)
|
||
push!(new, el)
|
||
return grow_to!(new, itr, st)
|
||
end
|
||
end
|
||
return dest
|
||
end
|
||
|
||
## Iteration ##
|
||
start(A::Array) = 1
|
||
next(a::Array,i) = (@_propagate_inbounds_meta; (a[i],i+1))
|
||
done(a::Array,i) = (@_inline_meta; i == length(a)+1)
|
||
|
||
## Indexing: getindex ##
|
||
|
||
# This is more complicated than it needs to be in order to get Win64 through bootstrap
|
||
getindex(A::Array, i1::Int) = arrayref(A, i1)
|
||
getindex(A::Array, i1::Int, i2::Int, I::Int...) = (@_inline_meta; arrayref(A, i1, i2, I...)) # TODO: REMOVE FOR #14770
|
||
|
||
# Faster contiguous indexing using copy! for UnitRange and Colon
|
||
function getindex(A::Array, I::UnitRange{Int})
|
||
@_inline_meta
|
||
@boundscheck checkbounds(A, I)
|
||
lI = length(I)
|
||
X = similar(A, lI)
|
||
if lI > 0
|
||
unsafe_copy!(X, 1, A, first(I), lI)
|
||
end
|
||
return X
|
||
end
|
||
function getindex(A::Array, c::Colon)
|
||
lI = length(A)
|
||
X = similar(A, lI)
|
||
if lI > 0
|
||
unsafe_copy!(X, 1, A, 1, lI)
|
||
end
|
||
return X
|
||
end
|
||
|
||
# This is redundant with the abstract fallbacks, but needed for bootstrap
|
||
function getindex(A::Array{S}, I::Range{Int}) where S
|
||
return S[ A[i] for i in I ]
|
||
end
|
||
|
||
## Indexing: setindex! ##
|
||
setindex!(A::Array{T}, x, i1::Int) where {T} = arrayset(A, convert(T,x)::T, i1)
|
||
setindex!(A::Array{T}, x, i1::Int, i2::Int, I::Int...) where {T} = (@_inline_meta; arrayset(A, convert(T,x)::T, i1, i2, I...)) # TODO: REMOVE FOR #14770
|
||
|
||
# These are redundant with the abstract fallbacks but needed for bootstrap
|
||
function setindex!(A::Array, x, I::AbstractVector{Int})
|
||
@_propagate_inbounds_meta
|
||
A === I && (I = copy(I))
|
||
for i in I
|
||
A[i] = x
|
||
end
|
||
return A
|
||
end
|
||
function setindex!(A::Array, X::AbstractArray, I::AbstractVector{Int})
|
||
@_propagate_inbounds_meta
|
||
@boundscheck setindex_shape_check(X, length(I))
|
||
count = 1
|
||
if X === A
|
||
X = copy(X)
|
||
I===A && (I = X::typeof(I))
|
||
elseif I === A
|
||
I = copy(I)
|
||
end
|
||
for i in I
|
||
@inbounds x = X[count]
|
||
A[i] = x
|
||
count += 1
|
||
end
|
||
return A
|
||
end
|
||
|
||
# Faster contiguous setindex! with copy!
|
||
function setindex!(A::Array{T}, X::Array{T}, I::UnitRange{Int}) where T
|
||
@_inline_meta
|
||
@boundscheck checkbounds(A, I)
|
||
lI = length(I)
|
||
@boundscheck setindex_shape_check(X, lI)
|
||
if lI > 0
|
||
unsafe_copy!(A, first(I), X, 1, lI)
|
||
end
|
||
return A
|
||
end
|
||
function setindex!(A::Array{T}, X::Array{T}, c::Colon) where T
|
||
@_inline_meta
|
||
lI = length(A)
|
||
@boundscheck setindex_shape_check(X, lI)
|
||
if lI > 0
|
||
unsafe_copy!(A, 1, X, 1, lI)
|
||
end
|
||
return A
|
||
end
|
||
|
||
setindex!(A::Array, x::Number, ::Colon) = fill!(A, x)
|
||
setindex!(A::Array{T, N}, x::Number, ::Vararg{Colon, N}) where {T, N} = fill!(A, x)
|
||
|
||
# efficiently grow an array
|
||
|
||
_growat!(a::Vector, i::Integer, delta::Integer) =
|
||
ccall(:jl_array_grow_at, Void, (Any, Int, UInt), a, i - 1, delta)
|
||
|
||
# efficiently delete part of an array
|
||
|
||
_deleteat!(a::Vector, i::Integer, delta::Integer) =
|
||
ccall(:jl_array_del_at, Void, (Any, Int, UInt), a, i - 1, delta)
|
||
|
||
## Dequeue functionality ##
|
||
|
||
function push!(a::Array{T,1}, item) where T
|
||
# convert first so we don't grow the array if the assignment won't work
|
||
itemT = convert(T, item)
|
||
ccall(:jl_array_grow_end, Void, (Any, UInt), a, 1)
|
||
a[end] = itemT
|
||
return a
|
||
end
|
||
|
||
function push!(a::Array{Any,1}, item::ANY)
|
||
ccall(:jl_array_grow_end, Void, (Any, UInt), a, 1)
|
||
arrayset(a, item, length(a))
|
||
return a
|
||
end
|
||
|
||
function append!(a::Array{<:Any,1}, items::AbstractVector)
|
||
itemindices = eachindex(items)
|
||
n = length(itemindices)
|
||
ccall(:jl_array_grow_end, Void, (Any, UInt), a, n)
|
||
copy!(a, length(a)-n+1, items, first(itemindices), n)
|
||
return a
|
||
end
|
||
|
||
append!(a::Vector, iter) = _append!(a, iteratorsize(iter), iter)
|
||
push!(a::Vector, iter...) = append!(a, iter)
|
||
|
||
function _append!(a, ::Union{HasLength,HasShape}, iter)
|
||
n = length(a)
|
||
resize!(a, n+length(iter))
|
||
@inbounds for (i,item) in zip(n+1:length(a), iter)
|
||
a[i] = item
|
||
end
|
||
a
|
||
end
|
||
|
||
function _append!(a, ::IteratorSize, iter)
|
||
for item in iter
|
||
push!(a, item)
|
||
end
|
||
a
|
||
end
|
||
|
||
"""
|
||
prepend!(a::Vector, items) -> collection
|
||
|
||
Insert the elements of `items` to the beginning of `a`.
|
||
|
||
# Example
|
||
```jldoctest
|
||
julia> prepend!([3],[1,2])
|
||
3-element Array{Int64,1}:
|
||
1
|
||
2
|
||
3
|
||
```
|
||
"""
|
||
function prepend! end
|
||
|
||
function prepend!(a::Array{<:Any,1}, items::AbstractVector)
|
||
itemindices = eachindex(items)
|
||
n = length(itemindices)
|
||
ccall(:jl_array_grow_beg, Void, (Any, UInt), a, n)
|
||
if a === items
|
||
copy!(a, 1, items, n+1, n)
|
||
else
|
||
copy!(a, 1, items, first(itemindices), n)
|
||
end
|
||
return a
|
||
end
|
||
|
||
prepend!(a::Vector, iter) = _prepend!(a, iteratorsize(iter), iter)
|
||
unshift!(a::Vector, iter...) = prepend!(a, iter)
|
||
|
||
function _prepend!(a, ::Union{HasLength,HasShape}, iter)
|
||
n = length(iter)
|
||
ccall(:jl_array_grow_beg, Void, (Any, UInt), a, n)
|
||
i = 0
|
||
for item in iter
|
||
@inbounds a[i += 1] = item
|
||
end
|
||
a
|
||
end
|
||
function _prepend!(a, ::IteratorSize, iter)
|
||
n = 0
|
||
for item in iter
|
||
n += 1
|
||
unshift!(a, item)
|
||
end
|
||
reverse!(a, 1, n)
|
||
a
|
||
end
|
||
|
||
|
||
"""
|
||
resize!(a::Vector, n::Integer) -> Vector
|
||
|
||
Resize `a` to contain `n` elements. If `n` is smaller than the current collection
|
||
length, the first `n` elements will be retained. If `n` is larger, the new elements are not
|
||
guaranteed to be initialized.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> resize!([6, 5, 4, 3, 2, 1], 3)
|
||
3-element Array{Int64,1}:
|
||
6
|
||
5
|
||
4
|
||
|
||
julia> a = resize!([6, 5, 4, 3, 2, 1], 8);
|
||
|
||
julia> length(a)
|
||
8
|
||
|
||
julia> a[1:6]
|
||
6-element Array{Int64,1}:
|
||
6
|
||
5
|
||
4
|
||
3
|
||
2
|
||
1
|
||
```
|
||
"""
|
||
function resize!(a::Vector, nl::Integer)
|
||
l = length(a)
|
||
if nl > l
|
||
ccall(:jl_array_grow_end, Void, (Any, UInt), a, nl-l)
|
||
else
|
||
if nl < 0
|
||
throw(ArgumentError("new length must be ≥ 0"))
|
||
end
|
||
ccall(:jl_array_del_end, Void, (Any, UInt), a, l-nl)
|
||
end
|
||
return a
|
||
end
|
||
|
||
function sizehint!(a::Vector, sz::Integer)
|
||
ccall(:jl_array_sizehint, Void, (Any, UInt), a, sz)
|
||
a
|
||
end
|
||
|
||
function pop!(a::Vector)
|
||
if isempty(a)
|
||
throw(ArgumentError("array must be non-empty"))
|
||
end
|
||
item = a[end]
|
||
ccall(:jl_array_del_end, Void, (Any, UInt), a, 1)
|
||
return item
|
||
end
|
||
|
||
"""
|
||
unshift!(collection, items...) -> collection
|
||
|
||
Insert one or more `items` at the beginning of `collection`.
|
||
|
||
# Example
|
||
```jldoctest
|
||
julia> unshift!([1, 2, 3, 4], 5, 6)
|
||
6-element Array{Int64,1}:
|
||
5
|
||
6
|
||
1
|
||
2
|
||
3
|
||
4
|
||
```
|
||
"""
|
||
function unshift!(a::Array{T,1}, item) where T
|
||
item = convert(T, item)
|
||
ccall(:jl_array_grow_beg, Void, (Any, UInt), a, 1)
|
||
a[1] = item
|
||
return a
|
||
end
|
||
|
||
function shift!(a::Vector)
|
||
if isempty(a)
|
||
throw(ArgumentError("array must be non-empty"))
|
||
end
|
||
item = a[1]
|
||
ccall(:jl_array_del_beg, Void, (Any, UInt), a, 1)
|
||
return item
|
||
end
|
||
|
||
"""
|
||
insert!(a::Vector, index::Integer, item)
|
||
|
||
Insert an `item` into `a` at the given `index`. `index` is the index of `item` in
|
||
the resulting `a`.
|
||
|
||
# Example
|
||
```jldoctest
|
||
julia> insert!([6, 5, 4, 2, 1], 4, 3)
|
||
6-element Array{Int64,1}:
|
||
6
|
||
5
|
||
4
|
||
3
|
||
2
|
||
1
|
||
```
|
||
"""
|
||
function insert!(a::Array{T,1}, i::Integer, item) where T
|
||
# Throw convert error before changing the shape of the array
|
||
_item = convert(T, item)
|
||
_growat!(a, i, 1)
|
||
# _growat! already did bound check
|
||
@inbounds a[i] = _item
|
||
return a
|
||
end
|
||
|
||
"""
|
||
deleteat!(a::Vector, i::Integer)
|
||
|
||
Remove the item at the given `i` and return the modified `a`. Subsequent items
|
||
are shifted to fill the resulting gap.
|
||
|
||
# Example
|
||
```jldoctest
|
||
julia> deleteat!([6, 5, 4, 3, 2, 1], 2)
|
||
5-element Array{Int64,1}:
|
||
6
|
||
4
|
||
3
|
||
2
|
||
1
|
||
```
|
||
"""
|
||
deleteat!(a::Vector, i::Integer) = (_deleteat!(a, i, 1); a)
|
||
|
||
function deleteat!(a::Vector, r::UnitRange{<:Integer})
|
||
n = length(a)
|
||
isempty(r) || _deleteat!(a, first(r), length(r))
|
||
return a
|
||
end
|
||
|
||
"""
|
||
deleteat!(a::Vector, inds)
|
||
|
||
Remove the items at the indices given by `inds`, and return the modified `a`.
|
||
Subsequent items are shifted to fill the resulting gap.
|
||
|
||
`inds` can be either an iterator or a collection of sorted and unique integer indices,
|
||
or a boolean vector of the same length as `a` with `true` indicating entries to delete.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> deleteat!([6, 5, 4, 3, 2, 1], 1:2:5)
|
||
3-element Array{Int64,1}:
|
||
5
|
||
3
|
||
1
|
||
|
||
julia> deleteat!([6, 5, 4, 3, 2, 1], [true, false, true, false, true, false])
|
||
3-element Array{Int64,1}:
|
||
5
|
||
3
|
||
1
|
||
|
||
julia> deleteat!([6, 5, 4, 3, 2, 1], (2, 2))
|
||
ERROR: ArgumentError: indices must be unique and sorted
|
||
Stacktrace:
|
||
[1] _deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:921
|
||
[2] deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:908
|
||
```
|
||
"""
|
||
deleteat!(a::Vector, inds) = _deleteat!(a, inds)
|
||
deleteat!(a::Vector, inds::AbstractVector) = _deleteat!(a, to_indices(a, (inds,))[1])
|
||
|
||
function _deleteat!(a::Vector, inds)
|
||
n = length(a)
|
||
s = start(inds)
|
||
done(inds, s) && return a
|
||
(p, s) = next(inds, s)
|
||
q = p+1
|
||
while !done(inds, s)
|
||
(i,s) = next(inds, s)
|
||
if !(q <= i <= n)
|
||
if i < q
|
||
throw(ArgumentError("indices must be unique and sorted"))
|
||
else
|
||
throw(BoundsError())
|
||
end
|
||
end
|
||
while q < i
|
||
@inbounds a[p] = a[q]
|
||
p += 1; q += 1
|
||
end
|
||
q = i+1
|
||
end
|
||
while q <= n
|
||
@inbounds a[p] = a[q]
|
||
p += 1; q += 1
|
||
end
|
||
ccall(:jl_array_del_end, Void, (Any, UInt), a, n-p+1)
|
||
return a
|
||
end
|
||
|
||
# Simpler and more efficient version for logical indexing
|
||
function deleteat!(a::Vector, inds::AbstractVector{Bool})
|
||
n = length(a)
|
||
length(inds) == n || throw(BoundsError(a, inds))
|
||
p = 1
|
||
for (q, i) in enumerate(inds)
|
||
@inbounds a[p] = a[q]
|
||
p += !i
|
||
end
|
||
ccall(:jl_array_del_end, Void, (Any, UInt), a, n-p+1)
|
||
return a
|
||
end
|
||
|
||
const _default_splice = []
|
||
|
||
"""
|
||
splice!(a::Vector, index::Integer, [replacement]) -> item
|
||
|
||
Remove the item at the given index, and return the removed item.
|
||
Subsequent items are shifted left to fill the resulting gap.
|
||
If specified, replacement values from an ordered
|
||
collection will be spliced in place of the removed item.
|
||
|
||
# Examples
|
||
```jldoctest splice!
|
||
julia> A = [6, 5, 4, 3, 2, 1]; splice!(A, 5)
|
||
2
|
||
|
||
julia> A
|
||
5-element Array{Int64,1}:
|
||
6
|
||
5
|
||
4
|
||
3
|
||
1
|
||
|
||
julia> splice!(A, 5, -1)
|
||
1
|
||
|
||
julia> A
|
||
5-element Array{Int64,1}:
|
||
6
|
||
5
|
||
4
|
||
3
|
||
-1
|
||
|
||
julia> splice!(A, 1, [-1, -2, -3])
|
||
6
|
||
|
||
julia> A
|
||
7-element Array{Int64,1}:
|
||
-1
|
||
-2
|
||
-3
|
||
5
|
||
4
|
||
3
|
||
-1
|
||
```
|
||
|
||
To insert `replacement` before an index `n` without removing any items, use
|
||
`splice!(collection, n:n-1, replacement)`.
|
||
"""
|
||
function splice!(a::Vector, i::Integer, ins=_default_splice)
|
||
v = a[i]
|
||
m = length(ins)
|
||
if m == 0
|
||
_deleteat!(a, i, 1)
|
||
elseif m == 1
|
||
a[i] = ins[1]
|
||
else
|
||
_growat!(a, i, m-1)
|
||
k = 1
|
||
for x in ins
|
||
a[i+k-1] = x
|
||
k += 1
|
||
end
|
||
end
|
||
return v
|
||
end
|
||
|
||
"""
|
||
splice!(a::Vector, range, [replacement]) -> items
|
||
|
||
Remove items in the specified index range, and return a collection containing
|
||
the removed items.
|
||
Subsequent items are shifted left to fill the resulting gap.
|
||
If specified, replacement values from an ordered collection will be spliced in
|
||
place of the removed items.
|
||
|
||
To insert `replacement` before an index `n` without removing any items, use
|
||
`splice!(collection, n:n-1, replacement)`.
|
||
|
||
# Example
|
||
```jldoctest splice!
|
||
julia> splice!(A, 4:3, 2)
|
||
0-element Array{Int64,1}
|
||
|
||
julia> A
|
||
8-element Array{Int64,1}:
|
||
-1
|
||
-2
|
||
-3
|
||
2
|
||
5
|
||
4
|
||
3
|
||
-1
|
||
```
|
||
"""
|
||
function splice!(a::Vector, r::UnitRange{<:Integer}, ins=_default_splice)
|
||
v = a[r]
|
||
m = length(ins)
|
||
if m == 0
|
||
deleteat!(a, r)
|
||
return v
|
||
end
|
||
|
||
n = length(a)
|
||
f = first(r)
|
||
l = last(r)
|
||
d = length(r)
|
||
|
||
if m < d
|
||
delta = d - m
|
||
_deleteat!(a, (f - 1 < n - l) ? f : (l - delta + 1), delta)
|
||
elseif m > d
|
||
_growat!(a, (f - 1 < n - l) ? f : (l + 1), m - d)
|
||
end
|
||
|
||
k = 1
|
||
for x in ins
|
||
a[f+k-1] = x
|
||
k += 1
|
||
end
|
||
return v
|
||
end
|
||
|
||
function empty!(a::Vector)
|
||
ccall(:jl_array_del_end, Void, (Any, UInt), a, length(a))
|
||
return a
|
||
end
|
||
|
||
# use memcmp for lexcmp on byte arrays
|
||
function lexcmp(a::Array{UInt8,1}, b::Array{UInt8,1})
|
||
c = ccall(:memcmp, Int32, (Ptr{UInt8}, Ptr{UInt8}, UInt),
|
||
a, b, min(length(a),length(b)))
|
||
return c < 0 ? -1 : c > 0 ? +1 : cmp(length(a),length(b))
|
||
end
|
||
|
||
# use memcmp for == on bit integer types
|
||
function ==(a::Array{T,N}, b::Array{T,N}) where T<:BitInteger where N
|
||
size(a) == size(b) && 0 == ccall(
|
||
:memcmp, Int32, (Ptr{T}, Ptr{T}, UInt), a, b, sizeof(T) * length(a))
|
||
end
|
||
|
||
# this is ~20% faster than the generic implementation above for very small arrays
|
||
function ==(a::Array{T,1}, b::Array{T,1}) where T<:BitInteger
|
||
len = length(a)
|
||
len == length(b) && 0 == ccall(
|
||
:memcmp, Int32, (Ptr{T}, Ptr{T}, UInt), a, b, sizeof(T) * len)
|
||
end
|
||
|
||
function reverse(A::AbstractVector, s=first(linearindices(A)), n=last(linearindices(A)))
|
||
B = similar(A)
|
||
for i = first(linearindices(A)):s-1
|
||
B[i] = A[i]
|
||
end
|
||
for i = s:n
|
||
B[i] = A[n+s-i]
|
||
end
|
||
for i = n+1:last(linearindices(A))
|
||
B[i] = A[i]
|
||
end
|
||
return B
|
||
end
|
||
function reverseind(a::AbstractVector, i::Integer)
|
||
li = linearindices(a)
|
||
first(li) + last(li) - i
|
||
end
|
||
|
||
function reverse!(v::AbstractVector, s=first(linearindices(v)), n=last(linearindices(v)))
|
||
liv = linearindices(v)
|
||
if n <= s # empty case; ok
|
||
elseif !(first(liv) ≤ s ≤ last(liv))
|
||
throw(BoundsError(v, s))
|
||
elseif !(first(liv) ≤ n ≤ last(liv))
|
||
throw(BoundsError(v, n))
|
||
end
|
||
r = n
|
||
@inbounds for i in s:div(s+n-1, 2)
|
||
v[i], v[r] = v[r], v[i]
|
||
r -= 1
|
||
end
|
||
return v
|
||
end
|
||
|
||
|
||
# concatenations of homogeneous combinations of vectors, horizontal and vertical
|
||
|
||
vcat() = Array{Any,1}(0)
|
||
hcat() = Array{Any,1}(0)
|
||
|
||
function hcat(V::Vector{T}...) where T
|
||
height = length(V[1])
|
||
for j = 2:length(V)
|
||
if length(V[j]) != height
|
||
throw(DimensionMismatch("vectors must have same lengths"))
|
||
end
|
||
end
|
||
return [ V[j][i]::T for i=1:length(V[1]), j=1:length(V) ]
|
||
end
|
||
|
||
function vcat(arrays::Vector{T}...) where T
|
||
n = 0
|
||
for a in arrays
|
||
n += length(a)
|
||
end
|
||
arr = Array{T,1}(n)
|
||
ptr = pointer(arr)
|
||
if isbits(T)
|
||
elsz = Core.sizeof(T)
|
||
else
|
||
elsz = Core.sizeof(Ptr{Void})
|
||
end
|
||
for a in arrays
|
||
na = length(a)
|
||
nba = na * elsz
|
||
if isbits(T)
|
||
ccall(:memcpy, Ptr{Void}, (Ptr{Void}, Ptr{Void}, UInt),
|
||
ptr, a, nba)
|
||
else
|
||
ccall(:jl_array_ptr_copy, Void, (Any, Ptr{Void}, Any, Ptr{Void}, Int),
|
||
arr, ptr, a, pointer(a), na)
|
||
end
|
||
ptr += nba
|
||
end
|
||
return arr
|
||
end
|
||
|
||
cat(n::Integer, x::Integer...) = reshape([x...], (ntuple(x->1, n-1)..., length(x)))
|
||
|
||
|
||
## find ##
|
||
|
||
"""
|
||
findnext(A, i::Integer)
|
||
|
||
Find the next linear index >= `i` of a non-zero element of `A`, or `0` if not found.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> A = [0 0; 1 0]
|
||
2×2 Array{Int64,2}:
|
||
0 0
|
||
1 0
|
||
|
||
julia> findnext(A,1)
|
||
2
|
||
|
||
julia> findnext(A,3)
|
||
0
|
||
```
|
||
"""
|
||
function findnext(A, start::Integer)
|
||
for i = start:length(A)
|
||
if A[i] != 0
|
||
return i
|
||
end
|
||
end
|
||
return 0
|
||
end
|
||
|
||
"""
|
||
findfirst(A)
|
||
|
||
Return the linear index of the first non-zero value in `A` (determined by `A[i]!=0`).
|
||
Returns `0` if no such value is found.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> A = [0 0; 1 0]
|
||
2×2 Array{Int64,2}:
|
||
0 0
|
||
1 0
|
||
|
||
julia> findfirst(A)
|
||
2
|
||
|
||
julia> findfirst(zeros(3))
|
||
0
|
||
```
|
||
"""
|
||
findfirst(A) = findnext(A, 1)
|
||
|
||
"""
|
||
findnext(A, v, i::Integer)
|
||
|
||
Find the next linear index >= `i` of an element of `A` equal to `v` (using `==`), or `0` if not found.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> A = [1 4; 2 2]
|
||
2×2 Array{Int64,2}:
|
||
1 4
|
||
2 2
|
||
|
||
julia> findnext(A,4,4)
|
||
0
|
||
|
||
julia> findnext(A,4,3)
|
||
3
|
||
```
|
||
"""
|
||
function findnext(A, v, start::Integer)
|
||
for i = start:length(A)
|
||
if A[i] == v
|
||
return i
|
||
end
|
||
end
|
||
return 0
|
||
end
|
||
"""
|
||
findfirst(A, v)
|
||
|
||
Return the linear index of the first element equal to `v` in `A`.
|
||
Returns `0` if `v` is not found.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> A = [4 6; 2 2]
|
||
2×2 Array{Int64,2}:
|
||
4 6
|
||
2 2
|
||
|
||
julia> findfirst(A,2)
|
||
2
|
||
|
||
julia> findfirst(A,3)
|
||
0
|
||
```
|
||
"""
|
||
findfirst(A, v) = findnext(A, v, 1)
|
||
|
||
"""
|
||
findnext(predicate::Function, A, i::Integer)
|
||
|
||
Find the next linear index >= `i` of an element of `A` for which `predicate` returns `true`, or `0` if not found.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> A = [1 4; 2 2]
|
||
2×2 Array{Int64,2}:
|
||
1 4
|
||
2 2
|
||
|
||
julia> findnext(isodd, A, 1)
|
||
1
|
||
|
||
julia> findnext(isodd, A, 2)
|
||
0
|
||
```
|
||
"""
|
||
function findnext(testf::Function, A, start::Integer)
|
||
for i = start:length(A)
|
||
if testf(A[i])
|
||
return i
|
||
end
|
||
end
|
||
return 0
|
||
end
|
||
|
||
"""
|
||
findfirst(predicate::Function, A)
|
||
|
||
Return the linear index of the first element of `A` for which `predicate` returns `true`.
|
||
Returns `0` if there is no such element.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> A = [1 4; 2 2]
|
||
2×2 Array{Int64,2}:
|
||
1 4
|
||
2 2
|
||
|
||
julia> findfirst(iseven, A)
|
||
2
|
||
|
||
julia> findfirst(x -> x>10, A)
|
||
0
|
||
```
|
||
"""
|
||
findfirst(testf::Function, A) = findnext(testf, A, 1)
|
||
|
||
"""
|
||
findprev(A, i::Integer)
|
||
|
||
Find the previous linear index <= `i` of a non-zero element of `A`, or `0` if not found.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> A = [0 0; 1 2]
|
||
2×2 Array{Int64,2}:
|
||
0 0
|
||
1 2
|
||
|
||
julia> findprev(A,2)
|
||
2
|
||
|
||
julia> findprev(A,1)
|
||
0
|
||
```
|
||
"""
|
||
function findprev(A, start::Integer)
|
||
for i = start:-1:1
|
||
A[i] != 0 && return i
|
||
end
|
||
return 0
|
||
end
|
||
|
||
"""
|
||
findlast(A)
|
||
|
||
Return the linear index of the last non-zero value in `A` (determined by `A[i]!=0`).
|
||
Returns `0` if there is no non-zero value in `A`.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> A = [1 0; 1 0]
|
||
2×2 Array{Int64,2}:
|
||
1 0
|
||
1 0
|
||
|
||
julia> findlast(A)
|
||
2
|
||
|
||
julia> A = zeros(2,2)
|
||
2×2 Array{Float64,2}:
|
||
0.0 0.0
|
||
0.0 0.0
|
||
|
||
julia> findlast(A)
|
||
0
|
||
```
|
||
"""
|
||
findlast(A) = findprev(A, length(A))
|
||
|
||
"""
|
||
findprev(A, v, i::Integer)
|
||
|
||
Find the previous linear index <= `i` of an element of `A` equal to `v` (using `==`), or `0` if not found.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> A = [0 0; 1 2]
|
||
2×2 Array{Int64,2}:
|
||
0 0
|
||
1 2
|
||
|
||
julia> findprev(A, 1, 4)
|
||
2
|
||
|
||
julia> findprev(A, 1, 1)
|
||
0
|
||
```
|
||
"""
|
||
function findprev(A, v, start::Integer)
|
||
for i = start:-1:1
|
||
A[i] == v && return i
|
||
end
|
||
return 0
|
||
end
|
||
|
||
"""
|
||
findlast(A, v)
|
||
|
||
Return the linear index of the last element equal to `v` in `A`.
|
||
Returns `0` if there is no element of `A` equal to `v`.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> A = [1 2; 2 1]
|
||
2×2 Array{Int64,2}:
|
||
1 2
|
||
2 1
|
||
|
||
julia> findlast(A,1)
|
||
4
|
||
|
||
julia> findlast(A,2)
|
||
3
|
||
|
||
julia> findlast(A,3)
|
||
0
|
||
```
|
||
"""
|
||
findlast(A, v) = findprev(A, v, length(A))
|
||
|
||
"""
|
||
findprev(predicate::Function, A, i::Integer)
|
||
|
||
Find the previous linear index <= `i` of an element of `A` for which `predicate` returns `true`, or
|
||
`0` if not found.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> A = [4 6; 1 2]
|
||
2×2 Array{Int64,2}:
|
||
4 6
|
||
1 2
|
||
|
||
julia> findprev(isodd, A, 1)
|
||
0
|
||
|
||
julia> findprev(isodd, A, 3)
|
||
2
|
||
```
|
||
"""
|
||
function findprev(testf::Function, A, start::Integer)
|
||
for i = start:-1:1
|
||
testf(A[i]) && return i
|
||
end
|
||
return 0
|
||
end
|
||
|
||
"""
|
||
findlast(predicate::Function, A)
|
||
|
||
Return the linear index of the last element of `A` for which `predicate` returns `true`.
|
||
Returns `0` if there is no such element.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> A = [1 2; 3 4]
|
||
2×2 Array{Int64,2}:
|
||
1 2
|
||
3 4
|
||
|
||
julia> findlast(isodd, A)
|
||
2
|
||
|
||
julia> findlast(x -> x > 5, A)
|
||
0
|
||
```
|
||
"""
|
||
findlast(testf::Function, A) = findprev(testf, A, length(A))
|
||
|
||
"""
|
||
find(f::Function, A)
|
||
|
||
Return a vector `I` of the linear indexes of `A` where `f(A[I])` returns `true`.
|
||
If there are no such elements of `A`, find returns an empty array.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> A = [1 2; 3 4]
|
||
2×2 Array{Int64,2}:
|
||
1 2
|
||
3 4
|
||
|
||
julia> find(isodd,A)
|
||
2-element Array{Int64,1}:
|
||
1
|
||
2
|
||
|
||
julia> find(isodd, [2, 4])
|
||
0-element Array{Int64,1}
|
||
```
|
||
"""
|
||
function find(testf::Function, A)
|
||
# use a dynamic-length array to store the indexes, then copy to a non-padded
|
||
# array for the return
|
||
tmpI = Array{Int,1}(0)
|
||
inds = _index_remapper(A)
|
||
for (i,a) = enumerate(A)
|
||
if testf(a)
|
||
push!(tmpI, inds[i])
|
||
end
|
||
end
|
||
I = Array{Int,1}(length(tmpI))
|
||
copy!(I, tmpI)
|
||
return I
|
||
end
|
||
_index_remapper(A::AbstractArray) = linearindices(A)
|
||
_index_remapper(iter) = OneTo(typemax(Int)) # safe for objects that don't implement length
|
||
|
||
"""
|
||
find(A)
|
||
|
||
Return a vector of the linear indexes of the non-zeros in `A` (determined by `A[i]!=0`). A
|
||
common use of this is to convert a boolean array to an array of indexes of the `true`
|
||
elements. If there are no non-zero elements of `A`, `find` returns an empty array.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> A = [true false; false true]
|
||
2×2 Array{Bool,2}:
|
||
true false
|
||
false true
|
||
|
||
julia> find(A)
|
||
2-element Array{Int64,1}:
|
||
1
|
||
4
|
||
|
||
julia> find(zeros(3))
|
||
0-element Array{Int64,1}
|
||
```
|
||
"""
|
||
function find(A)
|
||
nnzA = countnz(A)
|
||
I = Vector{Int}(nnzA)
|
||
count = 1
|
||
inds = _index_remapper(A)
|
||
for (i,a) in enumerate(A)
|
||
if a != 0
|
||
I[count] = inds[i]
|
||
count += 1
|
||
end
|
||
end
|
||
return I
|
||
end
|
||
|
||
find(x::Number) = x == 0 ? Array{Int,1}(0) : [1]
|
||
find(testf::Function, x::Number) = !testf(x) ? Array{Int,1}(0) : [1]
|
||
|
||
findn(A::AbstractVector) = find(A)
|
||
|
||
"""
|
||
findn(A)
|
||
|
||
Return a vector of indexes for each dimension giving the locations of the non-zeros in `A`
|
||
(determined by `A[i]!=0`).
|
||
If there are no non-zero elements of `A`, `findn` returns a 2-tuple of empty arrays.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> A = [1 2 0; 0 0 3; 0 4 0]
|
||
3×3 Array{Int64,2}:
|
||
1 2 0
|
||
0 0 3
|
||
0 4 0
|
||
|
||
julia> findn(A)
|
||
([1, 1, 3, 2], [1, 2, 2, 3])
|
||
|
||
julia> A = zeros(2,2)
|
||
2×2 Array{Float64,2}:
|
||
0.0 0.0
|
||
0.0 0.0
|
||
|
||
julia> findn(A)
|
||
(Int64[], Int64[])
|
||
```
|
||
"""
|
||
function findn(A::AbstractMatrix)
|
||
nnzA = countnz(A)
|
||
I = similar(A, Int, nnzA)
|
||
J = similar(A, Int, nnzA)
|
||
count = 1
|
||
for j=indices(A,2), i=indices(A,1)
|
||
if A[i,j] != 0
|
||
I[count] = i
|
||
J[count] = j
|
||
count += 1
|
||
end
|
||
end
|
||
return (I, J)
|
||
end
|
||
|
||
"""
|
||
findnz(A)
|
||
|
||
Return a tuple `(I, J, V)` where `I` and `J` are the row and column indexes of the non-zero
|
||
values in matrix `A`, and `V` is a vector of the non-zero values.
|
||
|
||
# Example
|
||
```jldoctest
|
||
julia> A = [1 2 0; 0 0 3; 0 4 0]
|
||
3×3 Array{Int64,2}:
|
||
1 2 0
|
||
0 0 3
|
||
0 4 0
|
||
|
||
julia> findnz(A)
|
||
([1, 1, 3, 2], [1, 2, 2, 3], [1, 2, 4, 3])
|
||
```
|
||
"""
|
||
function findnz(A::AbstractMatrix{T}) where T
|
||
nnzA = countnz(A)
|
||
I = zeros(Int, nnzA)
|
||
J = zeros(Int, nnzA)
|
||
NZs = Array{T,1}(nnzA)
|
||
count = 1
|
||
if nnzA > 0
|
||
for j=indices(A,2), i=indices(A,1)
|
||
Aij = A[i,j]
|
||
if Aij != 0
|
||
I[count] = i
|
||
J[count] = j
|
||
NZs[count] = Aij
|
||
count += 1
|
||
end
|
||
end
|
||
end
|
||
return (I, J, NZs)
|
||
end
|
||
|
||
"""
|
||
findmax(itr) -> (x, index)
|
||
|
||
Returns the maximum element of the collection `itr` and its index. If there are multiple
|
||
maximal elements, then the first one will be returned. `NaN` values are ignored, unless
|
||
all elements are `NaN`.
|
||
|
||
The collection must not be empty.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> findmax([8,0.1,-9,pi])
|
||
(8.0, 1)
|
||
|
||
julia> findmax([1,7,7,6])
|
||
(7, 2)
|
||
|
||
julia> findmax([1,7,7,NaN])
|
||
(7.0, 2)
|
||
```
|
||
"""
|
||
function findmax(a)
|
||
if isempty(a)
|
||
throw(ArgumentError("collection must be non-empty"))
|
||
end
|
||
s = start(a)
|
||
mi = i = 1
|
||
m, s = next(a, s)
|
||
while !done(a, s)
|
||
ai, s = next(a, s)
|
||
i += 1
|
||
if ai > m || m!=m
|
||
m = ai
|
||
mi = i
|
||
end
|
||
end
|
||
return (m, mi)
|
||
end
|
||
|
||
"""
|
||
findmin(itr) -> (x, index)
|
||
|
||
Returns the minimum element of the collection `itr` and its index. If there are multiple
|
||
minimal elements, then the first one will be returned. `NaN` values are ignored, unless
|
||
all elements are `NaN`.
|
||
|
||
The collection must not be empty.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> findmin([8,0.1,-9,pi])
|
||
(-9.0, 3)
|
||
|
||
julia> findmin([7,1,1,6])
|
||
(1, 2)
|
||
|
||
julia> findmin([7,1,1,NaN])
|
||
(1.0, 2)
|
||
```
|
||
"""
|
||
function findmin(a)
|
||
if isempty(a)
|
||
throw(ArgumentError("collection must be non-empty"))
|
||
end
|
||
s = start(a)
|
||
mi = i = 1
|
||
m, s = next(a, s)
|
||
while !done(a, s)
|
||
ai, s = next(a, s)
|
||
i += 1
|
||
if ai < m || m!=m
|
||
m = ai
|
||
mi = i
|
||
end
|
||
end
|
||
return (m, mi)
|
||
end
|
||
|
||
"""
|
||
indmax(itr) -> Integer
|
||
|
||
Returns the index of the maximum element in a collection. If there are multiple maximal
|
||
elements, then the first one will be returned. `NaN` values are ignored, unless all
|
||
elements are `NaN`.
|
||
|
||
The collection must not be empty.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> indmax([8,0.1,-9,pi])
|
||
1
|
||
|
||
julia> indmax([1,7,7,6])
|
||
2
|
||
|
||
julia> indmax([1,7,7,NaN])
|
||
2
|
||
```
|
||
"""
|
||
indmax(a) = findmax(a)[2]
|
||
|
||
"""
|
||
indmin(itr) -> Integer
|
||
|
||
Returns the index of the minimum element in a collection. If there are multiple minimal
|
||
elements, then the first one will be returned. `NaN` values are ignored, unless all
|
||
elements are `NaN`.
|
||
|
||
The collection must not be empty.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> indmin([8,0.1,-9,pi])
|
||
3
|
||
|
||
julia> indmin([7,1,1,6])
|
||
2
|
||
|
||
julia> indmin([7,1,1,NaN])
|
||
2
|
||
```
|
||
"""
|
||
indmin(a) = findmin(a)[2]
|
||
|
||
# similar to Matlab's ismember
|
||
"""
|
||
indexin(a, b)
|
||
|
||
Returns a vector containing the highest index in `b` for
|
||
each value in `a` that is a member of `b` . The output
|
||
vector contains 0 wherever `a` is not a member of `b`.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> a = ['a', 'b', 'c', 'b', 'd', 'a'];
|
||
|
||
julia> b = ['a','b','c'];
|
||
|
||
julia> indexin(a,b)
|
||
6-element Array{Int64,1}:
|
||
1
|
||
2
|
||
3
|
||
2
|
||
0
|
||
1
|
||
|
||
julia> indexin(b,a)
|
||
3-element Array{Int64,1}:
|
||
6
|
||
4
|
||
3
|
||
```
|
||
"""
|
||
function indexin(a::AbstractArray, b::AbstractArray)
|
||
bdict = Dict(zip(b, 1:length(b)))
|
||
[get(bdict, i, 0) for i in a]
|
||
end
|
||
|
||
"""
|
||
findin(a, b)
|
||
|
||
Returns the indices of elements in collection `a` that appear in collection `b`.
|
||
|
||
# Examples
|
||
```jldoctest
|
||
julia> a = collect(1:3:15)
|
||
5-element Array{Int64,1}:
|
||
1
|
||
4
|
||
7
|
||
10
|
||
13
|
||
|
||
julia> b = collect(2:4:10)
|
||
3-element Array{Int64,1}:
|
||
2
|
||
6
|
||
10
|
||
|
||
julia> findin(a,b) # 10 is the only common element
|
||
1-element Array{Int64,1}:
|
||
4
|
||
```
|
||
"""
|
||
function findin(a, b)
|
||
ind = Array{Int,1}(0)
|
||
bset = Set(b)
|
||
@inbounds for (i,ai) in enumerate(a)
|
||
ai in bset && push!(ind, i)
|
||
end
|
||
ind
|
||
end
|
||
|
||
# Copying subregions
|
||
# TODO: DEPRECATE FOR #14770
|
||
function indcopy(sz::Dims, I::Vector)
|
||
n = length(I)
|
||
s = sz[n]
|
||
for i = n+1:length(sz)
|
||
s *= sz[i]
|
||
end
|
||
dst = eltype(I)[findin(I[i], i < n ? (1:sz[i]) : (1:s)) for i = 1:n]
|
||
src = eltype(I)[I[i][findin(I[i], i < n ? (1:sz[i]) : (1:s))] for i = 1:n]
|
||
dst, src
|
||
end
|
||
|
||
function indcopy(sz::Dims, I::Tuple{Vararg{RangeIndex}})
|
||
n = length(I)
|
||
s = sz[n]
|
||
for i = n+1:length(sz)
|
||
s *= sz[i]
|
||
end
|
||
dst::typeof(I) = ntuple(i-> findin(I[i], i < n ? (1:sz[i]) : (1:s)), n)::typeof(I)
|
||
src::typeof(I) = ntuple(i-> I[i][findin(I[i], i < n ? (1:sz[i]) : (1:s))], n)::typeof(I)
|
||
dst, src
|
||
end
|
||
|
||
## Filter ##
|
||
|
||
"""
|
||
filter(function, collection)
|
||
|
||
Return a copy of `collection`, removing elements for which `function` is `false`. For
|
||
associative collections, the function is passed two arguments (key and value).
|
||
|
||
# Examples
|
||
```jldocttest
|
||
julia> a = 1:10
|
||
1:10
|
||
|
||
julia> filter(isodd, a)
|
||
5-element Array{Int64,1}:
|
||
1
|
||
3
|
||
5
|
||
7
|
||
9
|
||
|
||
julia> d = Dict(1=>"a", 2=>"b")
|
||
Dict{Int64,String} with 2 entries:
|
||
2 => "b"
|
||
1 => "a"
|
||
|
||
julia> filter((x,y)->isodd(x), d)
|
||
Dict{Int64,String} with 1 entry:
|
||
1 => "a"
|
||
```
|
||
"""
|
||
filter(f, As::AbstractArray) = As[map(f, As)::AbstractArray{Bool}]
|
||
|
||
function filter!(f, a::AbstractVector)
|
||
isempty(a) && return a
|
||
|
||
idx = eachindex(a)
|
||
state = start(idx)
|
||
i, state = next(idx, state)
|
||
|
||
for acurr in a
|
||
if f(acurr)
|
||
a[i] = acurr
|
||
i, state = next(idx, state)
|
||
end
|
||
end
|
||
|
||
deleteat!(a, i:last(idx))
|
||
|
||
return a
|
||
end
|
||
|
||
function filter(f, a::Vector)
|
||
r = Vector{eltype(a)}(0)
|
||
for ai in a
|
||
if f(ai)
|
||
push!(r, ai)
|
||
end
|
||
end
|
||
return r
|
||
end
|
||
|
||
# set-like operators for vectors
|
||
# These are moderately efficient, preserve order, and remove dupes.
|
||
|
||
function intersect(v1, vs...)
|
||
ret = Vector{promote_eltype(v1, vs...)}(0)
|
||
for v_elem in v1
|
||
inall = true
|
||
for vsi in vs
|
||
if !in(v_elem, vsi)
|
||
inall=false; break
|
||
end
|
||
end
|
||
if inall
|
||
push!(ret, v_elem)
|
||
end
|
||
end
|
||
ret
|
||
end
|
||
|
||
function union(vs...)
|
||
ret = Vector{promote_eltype(vs...)}(0)
|
||
seen = Set()
|
||
for v in vs
|
||
for v_elem in v
|
||
if !in(v_elem, seen)
|
||
push!(ret, v_elem)
|
||
push!(seen, v_elem)
|
||
end
|
||
end
|
||
end
|
||
ret
|
||
end
|
||
# setdiff only accepts two args
|
||
|
||
"""
|
||
setdiff(a, b)
|
||
|
||
Construct the set of elements in `a` but not `b`. Maintains order with arrays. Note that
|
||
both arguments must be collections, and both will be iterated over. In particular,
|
||
`setdiff(set,element)` where `element` is a potential member of `set`, will not work in
|
||
general.
|
||
|
||
# Example
|
||
```jldoctest
|
||
julia> setdiff([1,2,3],[3,4,5])
|
||
2-element Array{Int64,1}:
|
||
1
|
||
2
|
||
```
|
||
"""
|
||
function setdiff(a, b)
|
||
args_type = promote_type(eltype(a), eltype(b))
|
||
bset = Set(b)
|
||
ret = Array{args_type,1}(0)
|
||
seen = Set{eltype(a)}()
|
||
for a_elem in a
|
||
if !in(a_elem, seen) && !in(a_elem, bset)
|
||
push!(ret, a_elem)
|
||
push!(seen, a_elem)
|
||
end
|
||
end
|
||
ret
|
||
end
|
||
# symdiff is associative, so a relatively clean
|
||
# way to implement this is by using setdiff and union, and
|
||
# recursing. Has the advantage of keeping order, too, but
|
||
# not as fast as other methods that make a single pass and
|
||
# store counts with a Dict.
|
||
symdiff(a) = a
|
||
symdiff(a, b) = union(setdiff(a,b), setdiff(b,a))
|
||
"""
|
||
symdiff(a, b, rest...)
|
||
|
||
Construct the symmetric difference of elements in the passed in sets or arrays.
|
||
Maintains order with arrays.
|
||
|
||
# Example
|
||
```jldoctest
|
||
julia> symdiff([1,2,3],[3,4,5],[4,5,6])
|
||
3-element Array{Int64,1}:
|
||
1
|
||
2
|
||
6
|
||
```
|
||
"""
|
||
symdiff(a, b, rest...) = symdiff(a, symdiff(b, rest...))
|