Skip to content

Commit ef596e7

Browse files
committed
Change findfirst/findlast/findnext/findprev to return the same index type as keys()
This is consistent with find(). We need to check whether the iterator is empty first, since calling first(keys(A)) may throw an error. Also add needed last(::EachStringIndex) and prevind(::AbstractArray, ::CartesianIndex) methods.
1 parent 11dcd63 commit ef596e7

File tree

8 files changed

+187
-69
lines changed

8 files changed

+187
-69
lines changed

NEWS.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -367,11 +367,12 @@ This section lists changes that do not have deprecation warnings.
367367
* `findn(x::AbstractArray)` has been deprecated in favor of `find(!iszero, x)`, which
368368
now returns cartesian indices for multidimensional arrays (see below, [#25532]).
369369

370-
* `find` now returns the same type of indices as `keys`/`pairs` for `AbstractArray`,
370+
* `find`, `findfirst`, `findlast`, `findnext` and `findprev` now take and/or return
371+
the same type of indices as `keys`/`pairs` for `AbstractArray`,
371372
`AbstractDict`, `AbstractString`, `Tuple` and `NamedTuple` objects ([#24774]).
372-
In particular, this means that it returns `CartesianIndex` objects for matrices
373+
In particular, this means that they return `CartesianIndex` objects for matrices
373374
and higher-dimensional arrays instead of linear indices as was previously the case.
374-
Use `LinearIndices(a)[find(f, a)]` to compute linear indices.
375+
Use `LinearIndices(a)[find(f, a)]` and similar constructs to compute linear indices.
375376

376377
* `AbstractSet` objects are now considered equal by `==` and `isequal` if all of their
377378
elements are equal ([#25368]). This has required changing the hashing algorithm

base/array.jl

+165-62
Original file line numberDiff line numberDiff line change
@@ -1497,21 +1497,35 @@ cat(n::Integer, x::Integer...) = reshape([x...], (ntuple(x->1, n-1)..., length(x
14971497
14981498
Find the next linear index >= `i` of a `true` element of `A`, or `nothing` if not found.
14991499
1500+
Indices are of the same type as those returned by [`keys(A)`](@ref)
1501+
and [`pairs(A)`](@ref).
1502+
15001503
# Examples
15011504
```jldoctest
1505+
julia> A = [false, false, true, false]
1506+
4-element Array{Bool,1}:
1507+
false
1508+
false
1509+
true
1510+
false
1511+
1512+
julia> findnext(A, 1)
1513+
3
1514+
1515+
julia> findnext(A, 4) == nothing
1516+
true
1517+
15021518
julia> A = [false false; true false]
15031519
2×2 Array{Bool,2}:
15041520
false false
15051521
true false
15061522
1507-
julia> findnext(A, 1)
1508-
2
1509-
1510-
julia> findnext(A, 3)
1523+
julia> findnext(A, CartesianIndex(1, 1))
1524+
CartesianIndex(2, 1)
15111525
```
15121526
"""
1513-
function findnext(A, start::Integer)
1514-
l = endof(A)
1527+
function findnext(A, start)
1528+
l = last(keys(A))
15151529
i = start
15161530
warned = false
15171531
while i <= l
@@ -1531,48 +1545,74 @@ end
15311545
"""
15321546
findfirst(A)
15331547
1534-
Return the linear index of the first `true` value in `A`.
1548+
Return the index of the first `true` value in `A`.
15351549
Return `nothing` if no such value is found.
15361550
To search for other kinds of values, pass a predicate as the first argument.
15371551
1552+
Indices are of the same type as those returned by [`keys(A)`](@ref)
1553+
and [`pairs(A)`](@ref).
1554+
15381555
# Examples
15391556
```jldoctest
1557+
julia> A = [false, false, true, false]
1558+
4-element Array{Bool,1}:
1559+
false
1560+
false
1561+
true
1562+
false
1563+
1564+
julia> findfirst(A)
1565+
3
1566+
1567+
julia> findfirst(falses(3)) == nothing
1568+
true
1569+
15401570
julia> A = [false false; true false]
15411571
2×2 Array{Bool,2}:
15421572
false false
15431573
true false
15441574
15451575
julia> findfirst(A)
1546-
2
1547-
1548-
julia> findfirst(falses(3)) == nothing
1549-
true
1576+
CartesianIndex(2, 1)
15501577
```
15511578
"""
1552-
findfirst(A) = findnext(A, 1)
1579+
findfirst(A) = isempty(A) ? nothing : findnext(A, first(keys(A)))
15531580

15541581
"""
1555-
findnext(predicate::Function, A, i::Integer)
1582+
findnext(predicate::Function, A, i)
15561583
1557-
Find the next linear index >= `i` of an element of `A` for which `predicate` returns `true`,
1584+
Find the next index >= `i` of an element of `A` for which `predicate` returns `true`,
15581585
or `nothing` if not found.
15591586
1587+
Indices are of the same type as those returned by [`keys(A)`](@ref)
1588+
and [`pairs(A)`](@ref).
1589+
15601590
# Examples
15611591
```jldoctest
1562-
julia> A = [1 4; 2 2]
1563-
2×2 Array{Int64,2}:
1564-
1 4
1565-
2 2
1592+
A = [1, 4, 2, 2]
1593+
4-element Array{Int64,1}:
1594+
1
1595+
4
1596+
2
1597+
2
15661598
15671599
julia> findnext(isodd, A, 1)
15681600
1
15691601
15701602
julia> findnext(isodd, A, 2) == nothing
15711603
true
1604+
1605+
julia> A = [1 4; 2 2]
1606+
2×2 Array{Int64,2}:
1607+
1 4
1608+
2 2
1609+
1610+
julia> findnext(isodd, A, CartesianIndex(1, 1))
1611+
CartesianIndex(1, 1)
15721612
```
15731613
"""
1574-
function findnext(testf::Function, A, start::Integer)
1575-
l = endof(A)
1614+
function findnext(testf::Function, A, start)
1615+
l = last(keys(A))
15761616
i = start
15771617
while i <= l
15781618
if testf(A[i])
@@ -1586,15 +1626,20 @@ end
15861626
"""
15871627
findfirst(predicate::Function, A)
15881628
1589-
Return the linear index of the first element of `A` for which `predicate` returns `true`.
1629+
Return the index of the first element of `A` for which `predicate` returns `true`.
15901630
Return `nothing` if there is no such element.
15911631
1632+
Indices are of the same type as those returned by [`keys(A)`](@ref)
1633+
and [`pairs(A)`](@ref).
1634+
15921635
# Examples
15931636
```jldoctest
1594-
julia> A = [1 4; 2 2]
1595-
2×2 Array{Int64,2}:
1596-
1 4
1597-
2 2
1637+
julia> A = [1, 4, 2, 2]
1638+
4-element Array{Int64,1}:
1639+
1
1640+
4
1641+
2
1642+
2
15981643
15991644
julia> findfirst(iseven, A)
16001645
2
@@ -1603,34 +1648,55 @@ julia> findfirst(x -> x>10, A) == nothing
16031648
true
16041649
16051650
julia> findfirst(equalto(4), A)
1606-
3
1651+
2
1652+
1653+
julia> A = [1 4; 2 2]
1654+
2×2 Array{Int64,2}:
1655+
1 4
1656+
2 2
1657+
1658+
julia> findfirst(iseven, A)
1659+
CartesianIndex(2, 1)
16071660
```
16081661
"""
1609-
findfirst(testf::Function, A) = findnext(testf, A, 1)
1662+
findfirst(testf::Function, A) = isempty(A) ? nothing : findnext(testf, A, first(keys(A)))
16101663

16111664
"""
1612-
findprev(A, i::Integer)
1665+
findprev(A, i)
1666+
1667+
Find the previous index <= `i` of a `true` element of `A`, or `nothing` if not found.
16131668
1614-
Find the previous linear index <= `i` of a `true` element of `A`, or `nothing` if not found.
1669+
Indices are of the same type as those returned by [`keys(A)`](@ref)
1670+
and [`pairs(A)`](@ref).
16151671
16161672
# Examples
16171673
```jldoctest
1674+
julia> A = [false, false, true, true]
1675+
4-element Array{Bool,1}:
1676+
false
1677+
false
1678+
true
1679+
true
1680+
1681+
julia> findprev(A, 3)
1682+
3
1683+
1684+
julia> findprev(A, 1) == nothing
1685+
true
1686+
16181687
julia> A = [false false; true true]
16191688
2×2 Array{Bool,2}:
16201689
false false
16211690
true true
16221691
1623-
julia> findprev(A,2)
1624-
2
1625-
1626-
julia> findprev(A,1) == nothing
1627-
true
1692+
julia> findprev(A, CartesianIndex(2, 1))
1693+
CartesianIndex(2, 1)
16281694
```
16291695
"""
1630-
function findprev(A, start::Integer)
1696+
function findprev(A, start)
16311697
i = start
16321698
warned = false
1633-
while i >= 1
1699+
while i >= first(keys(A))
16341700
a = A[i]
16351701
if !warned && !(a isa Bool)
16361702
depwarn("In the future `findprev` will only work on boolean collections. Use `findprev(x->x!=0, A, start)` instead.", :findprev)
@@ -1645,50 +1711,76 @@ end
16451711
"""
16461712
findlast(A)
16471713
1648-
Return the linear index of the last `true` value in `A`.
1714+
Return the index of the last `true` value in `A`.
16491715
Return `nothing` if there is no `true` value in `A`.
16501716
1717+
Indices are of the same type as those returned by [`keys(A)`](@ref)
1718+
and [`pairs(A)`](@ref).
1719+
16511720
# Examples
16521721
```jldoctest
1653-
julia> A = [true false; true false]
1654-
2×2 Array{Bool,2}:
1655-
true false
1656-
true false
1722+
julia> A = [true, false, true, false]
1723+
4-element Array{Bool,1}:
1724+
true
1725+
false
1726+
true
1727+
false
16571728
16581729
julia> findlast(A)
1659-
2
1730+
3
16601731
16611732
julia> A = falses(2,2);
16621733
16631734
julia> findlast(A) == nothing
16641735
true
1736+
1737+
julia> A = [true false; true false]
1738+
2×2 Array{Bool,2}:
1739+
true false
1740+
true false
1741+
1742+
julia> findlast(A)
1743+
CartesianIndex(2, 1)
16651744
```
16661745
"""
1667-
findlast(A) = findprev(A, endof(A))
1746+
findlast(A) = isempty(A) ? nothing : findprev(A, last(keys(A)))
16681747

16691748
"""
1670-
findprev(predicate::Function, A, i::Integer)
1749+
findprev(predicate::Function, A, i)
16711750
1672-
Find the previous linear index <= `i` of an element of `A` for which `predicate` returns `true`, or
1751+
Find the previous index <= `i` of an element of `A` for which `predicate` returns `true`, or
16731752
`nothing` if not found.
16741753
1754+
Indices are of the same type as those returned by [`keys(A)`](@ref)
1755+
and [`pairs(A)`](@ref).
1756+
16751757
# Examples
16761758
```jldoctest
1677-
julia> A = [4 6; 1 2]
1678-
2×2 Array{Int64,2}:
1679-
4 6
1680-
1 2
1759+
julia> A = [4, 6, 1, 2]
1760+
4-element Array{Int64,1}:
1761+
4
1762+
6
1763+
1
1764+
2
16811765
16821766
julia> findprev(isodd, A, 1) == nothing
16831767
true
16841768
16851769
julia> findprev(isodd, A, 3)
1686-
2
1770+
3
1771+
1772+
julia> A = [4 6; 1 2]
1773+
2×2 Array{Int64,2}:
1774+
4 6
1775+
1 2
1776+
1777+
julia> findprev(isodd, A, CartesianIndex(1, 2))
1778+
CartesianIndex(2, 1)
16871779
```
16881780
"""
1689-
function findprev(testf::Function, A, start::Integer)
1781+
function findprev(testf::Function, A, start)
16901782
i = start
1691-
while i >= 1
1783+
while i >= first(keys(A))
16921784
testf(A[i]) && return i
16931785
i = prevind(A, i)
16941786
end
@@ -1698,35 +1790,46 @@ end
16981790
"""
16991791
findlast(predicate::Function, A)
17001792
1701-
Return the linear index of the last element of `A` for which `predicate` returns `true`.
1793+
Return the index of the last element of `A` for which `predicate` returns `true`.
17021794
Return `nothing` if there is no such element.
17031795
1796+
Indices are of the same type as those returned by [`keys(A)`](@ref)
1797+
and [`pairs(A)`](@ref).
1798+
17041799
# Examples
17051800
```jldoctest
1801+
julia> A = [1, 2, 3, 4]
1802+
4-element Array{Int64,1}:
1803+
1
1804+
2
1805+
3
1806+
4
1807+
1808+
julia> findlast(isodd, A)
1809+
3
1810+
1811+
julia> findlast(x -> x > 5, A) == nothing
1812+
true
1813+
17061814
julia> A = [1 2; 3 4]
17071815
2×2 Array{Int64,2}:
17081816
1 2
17091817
3 4
17101818
17111819
julia> findlast(isodd, A)
1712-
2
1713-
1714-
julia> findlast(x -> x > 5, A) == nothing
1715-
true
1820+
CartesianIndex(2, 1)
17161821
```
17171822
"""
1718-
findlast(testf::Function, A) = findprev(testf, A, endof(A))
1823+
findlast(testf::Function, A) = isempty(A) ? nothing : findprev(testf, A, last(keys(A)))
17191824

17201825
"""
17211826
find(f::Function, A)
17221827
17231828
Return a vector `I` of the indices or keys of `A` where `f(A[I])` returns `true`.
17241829
If there are no such elements of `A`, return an empty array.
17251830
1726-
Indices or keys are of the same type as those returned by [`keys(A)`](@ref)
1727-
and [`pairs(A)`](@ref) for `AbstractArray`, `AbstractDict`, `AbstractString`
1728-
`Tuple` and `NamedTuple` objects, and are linear indices starting at `1`
1729-
for other iterables.
1831+
Indices are of the same type as those returned by [`keys(A)`](@ref)
1832+
and [`pairs(A)`](@ref).
17301833
17311834
# Examples
17321835
```jldoctest

base/deprecated.jl

+3
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,9 @@ end
11841184
@deprecate findfirst(A, v) findfirst(equalto(v), A)
11851185
@deprecate findprev(A, v, i::Integer) findprev(equalto(v), A, i)
11861186
@deprecate findlast(A, v) findlast(equalto(v), A)
1187+
# to fix ambiguities introduced by deprecations
1188+
findnext(pred::Function, A, i::Integer) = invoke(findnext, Tuple{Function, Any, Any}, pred, A, i)
1189+
findprev(pred::Function, A, i::Integer) = invoke(findprev, Tuple{Function, Any, Any}, pred, A, i)
11871190
# also remove deprecation warnings in find* functions in array.jl, sparse/sparsematrix.jl,
11881191
# and sparse/sparsevector.jl.
11891192

0 commit comments

Comments
 (0)