Skip to content

Commit

Permalink
Add keytype+valtype method for AbstractArray and AbstractVector (J…
Browse files Browse the repository at this point in the history
…uliaLang#27749)

* Add keytype method for AbstractArray and AbstractVector

The function `keytype(a)` returns `eltype(keys(a))` for associative
structures; it should do the same for `Abstract{Array, Vector}`.

* Add keytype method for AbstractArray and AbstractVector (part 2)

Now also for the type, not just for objects.

* Add valtype(...) for arrays

Arrays are associative structures in the sense that keys(...)
and values(...) both work on them. When considering them as such, their
valtype should be equal to eltype. (A future version of Julia could
even do `const valtype = eltype`?)

* Implement keytype/valtype for object as keytype(typeof(...

As suggested by @mbauman in code review.

Co-Authored-By: tkluck <[email protected]>

* Implement keytype/valtype for ranges

* Add test cases for keytype/valtype(::AbstractArray)

* Add JuliaLang#27749 to NEWS.md

* keytype/valtype for arrays: docs + compat annotation

* keytype/valtype: use String values in examples

this makes the distinction between key and value clearer. Thanks to @StefanKarpinski for suggesting this.

Co-Authored-By: tkluck <[email protected]>

* keytype/valtype for arrays: no special treatment for ranges

This was a little red herring in the discussion in JuliaLang#27749:
the `length` of a range may depend on the type of its parameters,
but as it turns out, `eltype(keys(...))` does not.

That's arguably a bug/inconsistency, but it's outside of the
scope of this pull request to fix that.
tkluck authored and mbauman committed Apr 4, 2019
1 parent 0136fa1 commit ce17e05
Showing 4 changed files with 81 additions and 0 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -60,6 +60,8 @@ Standard library changes
* A no-argument construct to `Ptr{T}` has been added which constructs a null pointer ([#30919])
* `strip` now accepts a function argument in the same manner as `lstrip` and `rstrip` ([#31211])
* `mktempdir` now accepts a `prefix` keyword argument to customize the file name ([#31230], [#22922])
* `keytype` and `valtype` now work on `AbstractArray`, and return the `eltype` of `keys(...)` and
`values(...)` respectively ([#27749]).
* `nextfloat(::BigFloat)` and `prevfloat(::BigFloat)` now returns a value with the same precision
as their argument, which means that (in particular) `nextfloat(prevfloat(x)) == x` whereas
previously this could result in a completely different value with a different precision ([#31310])
45 changes: 45 additions & 0 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
@@ -101,6 +101,51 @@ unsafe_indices(r::AbstractRange) = (OneTo(unsafe_length(r)),) # Ranges use check
keys(a::AbstractArray) = CartesianIndices(axes(a))
keys(a::AbstractVector) = LinearIndices(a)

"""
keytype(T::Type{<:AbstractArray})
keytype(A::AbstractArray)
Return the key type of an array. This is equal to the
`eltype` of the result of `keys(...)`, and is provided
mainly for compatibility with the dictionary interface.
# Examples
```jldoctest
julia> keytype([1, 2, 3]) == Int
true
julia> keytype([1 2; 3 4])
CartesianIndex{2}
```
!!! compat "Julia 1.2"
For arrays, this function requires at least Julia 1.2.
"""
keytype(a::AbstractArray) = keytype(typeof(a))

keytype(A::Type{<:AbstractArray}) = CartesianIndex{ndims(A)}
keytype(A::Type{<:AbstractVector}) = Int

valtype(a::AbstractArray) = valtype(typeof(a))

"""
valtype(T::Type{<:AbstractArray})
valtype(A::AbstractArray)
Return the value type of an array. This is identical to `eltype` and is
provided mainly for compatibility with the dictionary interface.
# Examples
```jldoctest
julia> valtype(["one", "two", "three"])
String
```
!!! compat "Julia 1.2"
For arrays, this function requires at least Julia 1.2.
"""
valtype(A::Type{<:AbstractArray}) = eltype(A)

prevind(::AbstractArray, i::Integer) = Int(i)-1
nextind(::AbstractArray, i::Integer) = Int(i)+1

3 changes: 3 additions & 0 deletions test/abstractarray.jl
Original file line number Diff line number Diff line change
@@ -864,6 +864,9 @@ for A in (rand(2), rand(2,3))
@test A[i] == v
end
@test Array(values(A)) == A

@test keytype(A) == eltype(keys(A))
@test valtype(A) == eltype(values(A))
end

# nextind and prevind
31 changes: 31 additions & 0 deletions test/ranges.jl
Original file line number Diff line number Diff line change
@@ -259,6 +259,37 @@ end
@test length(Char(0):Char(0x001fffff)) == 2097152
@test length(typemax(UInt64)//one(UInt64):1:typemax(UInt64)//one(UInt64)) == 1
end
@testset "keys/values" begin
keytype_is_correct(r) = keytype(r) == eltype(keys(r))
valtype_is_correct(r) = valtype(r) == eltype(values(r))
@test keytype_is_correct(1:3)
@test keytype_is_correct(1:.3:4)
@test keytype_is_correct(.1:.1:.3)
@test keytype_is_correct(Int8(1):Int8(5))
@test keytype_is_correct(Int16(1):Int8(5))
@test keytype_is_correct(Int16(1):Int8(3):Int8(5))
@test keytype_is_correct(Int8(1):Int16(3):Int8(5))
@test keytype_is_correct(Int8(1):Int8(3):Int16(5))
@test keytype_is_correct(Int64(1):Int64(5))
@test keytype_is_correct(Int64(1):Int64(5))
@test keytype_is_correct(Int128(1):Int128(5))
@test keytype_is_correct(Base.OneTo(4))
@test keytype_is_correct(Base.OneTo(Int32(4)))

@test valtype_is_correct(1:3)
@test valtype_is_correct(1:.3:4)
@test valtype_is_correct(.1:.1:.3)
@test valtype_is_correct(Int8(1):Int8(5))
@test valtype_is_correct(Int16(1):Int8(5))
@test valtype_is_correct(Int16(1):Int8(3):Int8(5))
@test valtype_is_correct(Int8(1):Int16(3):Int8(5))
@test valtype_is_correct(Int8(1):Int8(3):Int16(5))
@test valtype_is_correct(Int64(1):Int64(5))
@test valtype_is_correct(Int64(1):Int64(5))
@test valtype_is_correct(Int128(1):Int128(5))
@test valtype_is_correct(Base.OneTo(4))
@test valtype_is_correct(Base.OneTo(Int32(4)))
end
@testset "findall(::Base.Fix2{typeof(in)}, ::Array)" begin
@test findall(in(3:20), [5.2, 3.3]) == findall(in(Vector(3:20)), [5.2, 3.3])

0 comments on commit ce17e05

Please sign in to comment.