Skip to content

Commit baa9a70

Browse files
committed
add pairs, and keys/values for arrays
This allows more uniform treatment of indexed collections.
1 parent 44fe78c commit baa9a70

File tree

14 files changed

+82
-31
lines changed

14 files changed

+82
-31
lines changed

base/abstractarray.jl

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ function indices(A)
6969
map(OneTo, size(A))
7070
end
7171

72-
# Performance optimization: get rid of a branch on `d` in `indices(A,
73-
# d)` for d=1. 1d arrays are heavily used, and the first dimension
74-
# comes up in other applications.
72+
# Performance optimization: get rid of a branch on `d` in `indices(A, d)`
73+
# for d=1. 1d arrays are heavily used, and the first dimension comes up
74+
# in other applications.
7575
indices1(A::AbstractArray{<:Any,0}) = OneTo(1)
7676
indices1(A::AbstractArray) = (@_inline_meta; indices(A)[1])
7777
indices1(iter) = OneTo(length(iter))
@@ -103,6 +103,10 @@ julia> extrema(b)
103103
"""
104104
linearindices(A) = (@_inline_meta; OneTo(_length(A)))
105105
linearindices(A::AbstractVector) = (@_inline_meta; indices1(A))
106+
107+
keys(a::AbstractArray) = CartesianRange(indices(a))
108+
keys(a::AbstractVector) = linearindices(a)
109+
106110
eltype(::Type{<:AbstractArray{E}}) where {E} = E
107111
elsize(::AbstractArray{T}) where {T} = sizeof(T)
108112

@@ -756,8 +760,11 @@ start(A::AbstractArray) = (@_inline_meta; itr = eachindex(A); (itr, start(itr)))
756760
next(A::AbstractArray, i) = (@_propagate_inbounds_meta; (idx, s) = next(i[1], i[2]); (A[idx], (i[1], s)))
757761
done(A::AbstractArray, i) = (@_propagate_inbounds_meta; done(i[1], i[2]))
758762

763+
# `eachindex` is mostly an optimization of `keys`
764+
eachindex(itrs...) = keys(itrs...)
765+
759766
# eachindex iterates over all indices. IndexCartesian definitions are later.
760-
eachindex(A::Union{Number,AbstractVector}) = (@_inline_meta(); indices1(A))
767+
eachindex(A::AbstractVector) = (@_inline_meta(); indices1(A))
761768

762769
"""
763770
eachindex(A...)
@@ -826,6 +833,9 @@ end
826833

827834
isempty(a::AbstractArray) = (_length(a) == 0)
828835

836+
# keys with an IndexStyle
837+
keys(s::IndexStyle, A::AbstractArray, B::AbstractArray...) = eachindex(s, A, B...)
838+
829839
## Conversions ##
830840

831841
convert(::Type{AbstractArray{T,N}}, A::AbstractArray{T,N}) where {T,N } = A

base/associative.jl

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,18 @@ end
6969

7070
in(k, v::KeyIterator) = get(v.dict, k, secret_table_token) !== secret_table_token
7171

72+
"""
73+
keys(iterator)
74+
75+
For an iterator or collection that has keys and values (e.g. arrays and dictionaries),
76+
return an iterator over the keys.
77+
"""
78+
function keys end
7279

7380
"""
7481
keys(a::Associative)
7582
76-
Return an iterator over all keys in a collection.
83+
Return an iterator over all keys in an associative collection.
7784
`collect(keys(a))` returns an array of keys.
7885
Since the keys are stored internally in a hash table,
7986
the order in which they are returned may vary.
@@ -94,7 +101,6 @@ julia> collect(keys(a))
94101
```
95102
"""
96103
keys(a::Associative) = KeyIterator(a)
97-
eachindex(a::Associative) = KeyIterator(a)
98104

99105
"""
100106
values(a::Associative)
@@ -121,6 +127,14 @@ julia> collect(values(a))
121127
"""
122128
values(a::Associative) = ValueIterator(a)
123129

130+
"""
131+
pairs(collection)
132+
133+
Return an iterator over `(index, value)` pairs for any
134+
collection that maps a set of indices to a set of values.
135+
"""
136+
pairs(collection) = zip(keys(collection), values(collection))
137+
124138
function copy(a::Associative)
125139
b = similar(a)
126140
for (k,v) in a

base/deprecated.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,6 +1736,11 @@ end
17361736

17371737
@deprecate promote_noncircular promote false
17381738

1739+
import .Iterators.enumerate
1740+
1741+
@deprecate enumerate(i::IndexLinear, A::AbstractArray) pairs(i, A)
1742+
@deprecate enumerate(i::IndexCartesian, A::AbstractArray) pairs(i, A)
1743+
17391744
# END 0.7 deprecations
17401745

17411746
# BEGIN 1.0 deprecations

base/essentials.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,3 +676,13 @@ false
676676
```
677677
"""
678678
isempty(itr) = done(itr, start(itr))
679+
680+
"""
681+
values(iterator)
682+
683+
For an iterator or collection that has keys and values, return an iterator
684+
over the values.
685+
This function simply returns its argument by default, since the elements
686+
of a general iterator are normally considered its "values".
687+
"""
688+
values(itr) = itr

base/exports.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,7 @@ export
688688
mapreducedim,
689689
merge!,
690690
merge,
691+
pairs,
691692
#pop!,
692693
#push!,
693694
reduce,

base/iterators.jl

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
module Iterators
44

5-
import Base: start, done, next, isempty, length, size, eltype, iteratorsize, iteratoreltype, indices, ndims
5+
import Base: start, done, next, isempty, length, size, eltype, iteratorsize, iteratoreltype, indices, ndims, pairs
66

77
using Base: tail, tuple_type_head, tuple_type_tail, tuple_type_cons, SizeUnknown, HasLength, HasShape,
88
IsInfinite, EltypeUnknown, HasEltype, OneTo, @propagate_inbounds
@@ -78,14 +78,16 @@ struct IndexValue{I,A<:AbstractArray}
7878
end
7979

8080
"""
81-
enumerate(IndexLinear(), A)
82-
enumerate(IndexCartesian(), A)
83-
enumerate(IndexStyle(A), A)
81+
pairs(IndexLinear(), A)
82+
pairs(IndexCartesian(), A)
83+
pairs(IndexStyle(A), A)
8484
8585
An iterator that accesses each element of the array `A`, returning
86-
`(i, x)`, where `i` is the index for the element and `x = A[i]`. This
87-
is similar to `enumerate(A)`, except `i` will always be a valid index
88-
for `A`.
86+
`(i, x)`, where `i` is the index for the element and `x = A[i]`.
87+
Identical to `pairs(A)`, except that the style of index can be selected.
88+
Also similar to `enumerate(A)`, except `i` will be a valid index
89+
for `A`, while `enumerate` always counts from 1 regardless of the indices
90+
of `A`.
8991
9092
Specifying `IndexLinear()` ensures that `i` will be an integer;
9193
specifying `IndexCartesian()` ensures that `i` will be a
@@ -96,7 +98,7 @@ been defined as the native indexing style for array `A`.
9698
```jldoctest
9799
julia> A = ["a" "d"; "b" "e"; "c" "f"];
98100
99-
julia> for (index, value) in enumerate(IndexStyle(A), A)
101+
julia> for (index, value) in pairs(IndexStyle(A), A)
100102
println("\$index \$value")
101103
end
102104
1 a
@@ -108,7 +110,7 @@ julia> for (index, value) in enumerate(IndexStyle(A), A)
108110
109111
julia> S = view(A, 1:2, :);
110112
111-
julia> for (index, value) in enumerate(IndexStyle(S), S)
113+
julia> for (index, value) in pairs(IndexStyle(S), S)
112114
println("\$index \$value")
113115
end
114116
CartesianIndex{2}((1, 1)) a
@@ -117,15 +119,14 @@ CartesianIndex{2}((1, 2)) d
117119
CartesianIndex{2}((2, 2)) e
118120
```
119121
120-
Note that `enumerate(A)` returns `i` as a *counter* (always starting
121-
at 1), whereas `enumerate(IndexLinear(), A)` returns `i` as an *index*
122-
(starting at the first linear index of `A`, which may or may not be
123-
1).
124-
125122
See also: [`IndexStyle`](@ref), [`indices`](@ref).
126123
"""
127-
enumerate(::IndexLinear, A::AbstractArray) = IndexValue(A, linearindices(A))
128-
enumerate(::IndexCartesian, A::AbstractArray) = IndexValue(A, CartesianRange(indices(A)))
124+
pairs(::IndexLinear, A::AbstractArray) = IndexValue(A, linearindices(A))
125+
pairs(::IndexCartesian, A::AbstractArray) = IndexValue(A, CartesianRange(indices(A)))
126+
127+
# faster than zip(keys(a), values(a)) for arrays
128+
pairs(A::AbstractArray) = pairs(IndexCartesian(), A)
129+
pairs(A::AbstractVector) = pairs(IndexLinear(), A)
129130

130131
length(v::IndexValue) = length(v.itr)
131132
indices(v::IndexValue) = indices(v.itr)

base/number.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ ndims(::Type{<:Number}) = 0
4949
length(x::Number) = 1
5050
endof(x::Number) = 1
5151
iteratorsize(::Type{<:Number}) = HasShape()
52+
keys(::Number) = OneTo(1)
5253

5354
getindex(x::Number) = x
5455
function getindex(x::Number, i::Integer)

base/process.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,7 @@ wait(x::ProcessChain) = for p in x.processes; wait(p); end
822822
show(io::IO, p::Process) = print(io, "Process(", p.cmd, ", ", process_status(p), ")")
823823

824824
# allow the elements of the Cmd to be accessed as an array or iterator
825-
for f in (:length, :endof, :start, :eachindex, :eltype, :first, :last)
825+
for f in (:length, :endof, :start, :keys, :eltype, :first, :last)
826826
@eval $f(cmd::Cmd) = $f(cmd.exec)
827827
end
828828
for f in (:next, :done, :getindex)

base/strings/basic.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ unsafe_chr2ind(s::AbstractString, i::Integer) = map_chr_ind(s, i, first, last)
316316
struct EachStringIndex{T<:AbstractString}
317317
s::T
318318
end
319-
eachindex(s::AbstractString) = EachStringIndex(s)
319+
keys(s::AbstractString) = EachStringIndex(s)
320320

321321
length(e::EachStringIndex) = length(e.s)
322322
start(e::EachStringIndex) = start(e.s)

base/test.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1415,7 +1415,7 @@ end
14151415
GenericArray{T}(args...) where {T} = GenericArray(Array{T}(args...))
14161416
GenericArray{T,N}(args...) where {T,N} = GenericArray(Array{T,N}(args...))
14171417

1418-
Base.eachindex(a::GenericArray) = eachindex(a.a)
1418+
Base.keys(a::GenericArray) = keys(a.a)
14191419
Base.indices(a::GenericArray) = indices(a.a)
14201420
Base.length(a::GenericArray) = length(a.a)
14211421
Base.size(a::GenericArray) = size(a.a)

0 commit comments

Comments
 (0)