Skip to content

Commit 1eb0827

Browse files
committed
require explicit predicates in find functions
fix #23120, fix #19186
1 parent ff9fb48 commit 1eb0827

28 files changed

+158
-191
lines changed

NEWS.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,9 @@ Library improvements
283283

284284
* REPL Undo via Ctrl-/ and Ctrl-_
285285

286+
* New function `equalto(x)`, which returns a function that compares its argument to `x`
287+
using `isequal` ([#23812]).
288+
286289
Compiler/Runtime improvements
287290
-----------------------------
288291

@@ -468,6 +471,12 @@ Deprecated or removed
468471
* The timing functions `tic`, `toc`, and `toq` are deprecated in favor of `@time` and `@elapsed`
469472
([#17046]).
470473

474+
* Methods of `findfirst`, `findnext`, `findlast`, and `findprev` that accept a value to
475+
search for are deprecated in favor of passing a predicate ([#19186], [#10593]).
476+
477+
* `find` functions now operate only on booleans by default. To look for non-zeros, use
478+
`x->x!=0` or `!iszero` ([#23120]).
479+
471480
Command-line option changes
472481
---------------------------
473482

base/array.jl

Lines changed: 52 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,14 +1596,14 @@ cat(n::Integer, x::Integer...) = reshape([x...], (ntuple(x->1, n-1)..., length(x
15961596
"""
15971597
findnext(A, i::Integer)
15981598
1599-
Find the next linear index >= `i` of a non-zero element of `A`, or `0` if not found.
1599+
Find the next linear index >= `i` of a `true` element of `A`, or `0` if not found.
16001600
16011601
# Examples
16021602
```jldoctest
1603-
julia> A = [0 0; 1 0]
1604-
2×2 Array{Int64,2}:
1605-
0 0
1606-
1 0
1603+
julia> A = [false false; true false]
1604+
2×2 Array{Bool,2}:
1605+
false false
1606+
true false
16071607
16081608
julia> findnext(A,1)
16091609
2
@@ -1615,8 +1615,14 @@ julia> findnext(A,3)
16151615
function findnext(A, start::Integer)
16161616
l = endof(A)
16171617
i = start
1618+
warned = false
16181619
while i <= l
1619-
if A[i] != 0
1620+
a = A[i]
1621+
if !warned && !(a isa Bool)
1622+
depwarn("In the future `findnext` will only work on boolean collections. Use `findnext(x->x!=0, A)` instead.", :findnext)
1623+
warned = true
1624+
end
1625+
if a != 0
16201626
return i
16211627
end
16221628
i = nextind(A, i)
@@ -1627,8 +1633,9 @@ end
16271633
"""
16281634
findfirst(A)
16291635
1630-
Return the linear index of the first non-zero value in `A` (determined by `A[i]!=0`).
1636+
Return the linear index of the first `true` value in `A`.
16311637
Returns `0` if no such value is found.
1638+
To search for other kinds of values, pass a predicate as the first argument.
16321639
16331640
# Examples
16341641
```jldoctest
@@ -1646,58 +1653,6 @@ julia> findfirst(zeros(3))
16461653
"""
16471654
findfirst(A) = findnext(A, 1)
16481655

1649-
"""
1650-
findnext(A, v, i::Integer)
1651-
1652-
Find the next linear index >= `i` of an element of `A` equal to `v` (using `==`), or `0` if not found.
1653-
1654-
# Examples
1655-
```jldoctest
1656-
julia> A = [1 4; 2 2]
1657-
2×2 Array{Int64,2}:
1658-
1 4
1659-
2 2
1660-
1661-
julia> findnext(A,4,4)
1662-
0
1663-
1664-
julia> findnext(A,4,3)
1665-
3
1666-
```
1667-
"""
1668-
function findnext(A, v, start::Integer)
1669-
l = endof(A)
1670-
i = start
1671-
while i <= l
1672-
if A[i] == v
1673-
return i
1674-
end
1675-
i = nextind(A, i)
1676-
end
1677-
return 0
1678-
end
1679-
"""
1680-
findfirst(A, v)
1681-
1682-
Return the linear index of the first element equal to `v` in `A`.
1683-
Returns `0` if `v` is not found.
1684-
1685-
# Examples
1686-
```jldoctest
1687-
julia> A = [4 6; 2 2]
1688-
2×2 Array{Int64,2}:
1689-
4 6
1690-
2 2
1691-
1692-
julia> findfirst(A,2)
1693-
2
1694-
1695-
julia> findfirst(A,3)
1696-
0
1697-
```
1698-
"""
1699-
findfirst(A, v) = findnext(A, v, 1)
1700-
17011656
"""
17021657
findnext(predicate::Function, A, i::Integer)
17031658
@@ -1747,21 +1702,24 @@ julia> findfirst(iseven, A)
17471702
17481703
julia> findfirst(x -> x>10, A)
17491704
0
1705+
1706+
julia> findfirst(equalto(4), A)
1707+
3
17501708
```
17511709
"""
17521710
findfirst(testf::Function, A) = findnext(testf, A, 1)
17531711

17541712
"""
17551713
findprev(A, i::Integer)
17561714
1757-
Find the previous linear index <= `i` of a non-zero element of `A`, or `0` if not found.
1715+
Find the previous linear index <= `i` of a `true` element of `A`, or `0` if not found.
17581716
17591717
# Examples
17601718
```jldoctest
1761-
julia> A = [0 0; 1 2]
1762-
2×2 Array{Int64,2}:
1763-
0 0
1764-
1 2
1719+
julia> A = [false false; true true]
1720+
2×2 Array{Bool,2}:
1721+
false false
1722+
true true
17651723
17661724
julia> findprev(A,2)
17671725
2
@@ -1772,8 +1730,14 @@ julia> findprev(A,1)
17721730
"""
17731731
function findprev(A, start::Integer)
17741732
i = start
1733+
warned = false
17751734
while i >= 1
1776-
A[i] != 0 && return i
1735+
a = A[i]
1736+
if !warned && !(a isa Bool)
1737+
depwarn("In the future `findprev` will only work on boolean collections. Use `findprev(x->x!=0, A)` instead.", :findprev)
1738+
warned = true
1739+
end
1740+
a != 0 && return i
17771741
i = prevind(A, i)
17781742
end
17791743
return 0
@@ -1782,8 +1746,8 @@ end
17821746
"""
17831747
findlast(A)
17841748
1785-
Return the linear index of the last non-zero value in `A` (determined by `A[i]!=0`).
1786-
Returns `0` if there is no non-zero value in `A`.
1749+
Return the linear index of the last `true` value in `A`.
1750+
Returns `0` if there is no `true` value in `A`.
17871751
17881752
# Examples
17891753
```jldoctest
@@ -1806,59 +1770,6 @@ julia> findlast(A)
18061770
"""
18071771
findlast(A) = findprev(A, endof(A))
18081772

1809-
"""
1810-
findprev(A, v, i::Integer)
1811-
1812-
Find the previous linear index <= `i` of an element of `A` equal to `v` (using `==`), or `0` if not found.
1813-
1814-
# Examples
1815-
```jldoctest
1816-
julia> A = [0 0; 1 2]
1817-
2×2 Array{Int64,2}:
1818-
0 0
1819-
1 2
1820-
1821-
julia> findprev(A, 1, 4)
1822-
2
1823-
1824-
julia> findprev(A, 1, 1)
1825-
0
1826-
```
1827-
"""
1828-
function findprev(A, v, start::Integer)
1829-
i = start
1830-
while i >= 1
1831-
A[i] == v && return i
1832-
i = prevind(A, i)
1833-
end
1834-
return 0
1835-
end
1836-
1837-
"""
1838-
findlast(A, v)
1839-
1840-
Return the linear index of the last element equal to `v` in `A`.
1841-
Returns `0` if there is no element of `A` equal to `v`.
1842-
1843-
# Examples
1844-
```jldoctest
1845-
julia> A = [1 2; 2 1]
1846-
2×2 Array{Int64,2}:
1847-
1 2
1848-
2 1
1849-
1850-
julia> findlast(A,1)
1851-
4
1852-
1853-
julia> findlast(A,2)
1854-
3
1855-
1856-
julia> findlast(A,3)
1857-
0
1858-
```
1859-
"""
1860-
findlast(A, v) = findprev(A, v, endof(A))
1861-
18621773
"""
18631774
findprev(predicate::Function, A, i::Integer)
18641775
@@ -1918,16 +1829,23 @@ If there are no such elements of `A`, find returns an empty array.
19181829
19191830
# Examples
19201831
```jldoctest
1921-
julia> A = [1 2; 3 4]
1922-
2 Array{Int64,2}:
1923-
1 2
1924-
3 4
1832+
julia> A = [1 2 0; 3 4 0]
1833+
3 Array{Int64,2}:
1834+
1 2 0
1835+
3 4 0
19251836
1926-
julia> find(isodd,A)
1837+
julia> find(isodd, A)
19271838
2-element Array{Int64,1}:
19281839
1
19291840
2
19301841
1842+
julia> find(!iszero, A)
1843+
4-element Array{Int64,1}:
1844+
1
1845+
2
1846+
3
1847+
4
1848+
19311849
julia> find(isodd, [2, 4])
19321850
0-element Array{Int64,1}
19331851
```
@@ -1952,9 +1870,8 @@ _index_remapper(iter) = OneTo(typemax(Int)) # safe for objects that don't imple
19521870
"""
19531871
find(A)
19541872
1955-
Return a vector of the linear indexes of the non-zeros in `A` (determined by `A[i]!=0`). A
1956-
common use of this is to convert a boolean array to an array of indexes of the `true`
1957-
elements. If there are no non-zero elements of `A`, `find` returns an empty array.
1873+
Return a vector of the linear indices of the `true` values in `A`.
1874+
To search for other kinds of values, pass a predicate as the first argument.
19581875
19591876
# Examples
19601877
```jldoctest
@@ -1968,7 +1885,7 @@ julia> find(A)
19681885
1
19691886
4
19701887
1971-
julia> find(zeros(3))
1888+
julia> find(falses(3))
19721889
0-element Array{Int64,1}
19731890
```
19741891
"""
@@ -1977,7 +1894,12 @@ function find(A)
19771894
I = Vector{Int}(nnzA)
19781895
cnt = 1
19791896
inds = _index_remapper(A)
1897+
warned = false
19801898
for (i,a) in enumerate(A)
1899+
if !warned && !(a isa Bool)
1900+
depwarn("In the future `find(A)` will only work on boolean collections. Use `find(x->x!=0, A)` instead.", :find)
1901+
warned = true
1902+
end
19811903
if a != 0
19821904
I[cnt] = inds[i]
19831905
cnt += 1
@@ -1986,7 +1908,7 @@ function find(A)
19861908
return I
19871909
end
19881910

1989-
find(x::Number) = x == 0 ? Array{Int,1}(0) : [1]
1911+
find(x::Bool) = x ? [1] : Array{Int,1}(0)
19901912
find(testf::Function, x::Number) = !testf(x) ? Array{Int,1}(0) : [1]
19911913

19921914
findn(A::AbstractVector) = find(A)

base/combinatorics.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ function permute!!(a, p::AbstractVector{<:Integer})
7575
count = 0
7676
start = 0
7777
while count < length(a)
78-
ptr = start = findnext(p, start+1)
78+
ptr = start = findnext(!iszero, p, start+1)
7979
temp = a[start]
8080
next = p[start]
8181
count += 1
@@ -125,7 +125,7 @@ function ipermute!!(a, p::AbstractVector{<:Integer})
125125
count = 0
126126
start = 0
127127
while count < length(a)
128-
start = findnext(p, start+1)
128+
start = findnext(!iszero, p, start+1)
129129
temp = a[start]
130130
next = p[start]
131131
count += 1

base/datafmt.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ function val_opts(opts)
370370
for (opt_name, opt_val) in opts
371371
in(opt_name, valid_opts) ||
372372
throw(ArgumentError("unknown option $opt_name"))
373-
opt_typ = valid_opt_types[findfirst(valid_opts, opt_name)]
373+
opt_typ = valid_opt_types[findfirst(equalto(opt_name), valid_opts)]
374374
isa(opt_val, opt_typ) ||
375375
throw(ArgumentError("$opt_name should be of type $opt_typ, got $(typeof(opt_val))"))
376376
d[opt_name] = opt_val

base/deprecated.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1855,6 +1855,14 @@ end
18551855
nothing
18561856
end
18571857

1858+
@deprecate find(x::Number) find(!iszero, x)
1859+
@deprecate findnext(A, v, i::Integer) findnext(equalto(v), A, i)
1860+
@deprecate findfirst(A, v) findfirst(equalto(v), A)
1861+
@deprecate findprev(A, v, i::Integer) findprev(equalto(v), A, i)
1862+
@deprecate findlast(A, v) findlast(equalto(v), A)
1863+
# also remove deprecation warnings in find* functions in array.jl, sparse/sparsematrix.jl,
1864+
# and sparse/sparsevector.jl.
1865+
18581866
# END 0.7 deprecations
18591867

18601868
# BEGIN 1.0 deprecations

base/event.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ function ensure_rescheduled(othertask::Task)
234234
# if the current task was queued,
235235
# also need to return it to the runnable state
236236
# before throwing an error
237-
i = findfirst(Workqueue, ct)
237+
i = findfirst(t->t===ct, Workqueue)
238238
i == 0 || deleteat!(Workqueue, i)
239239
ct.state = :runnable
240240
end

base/exports.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,7 @@ export
861861
identity,
862862
isbits,
863863
isequal,
864+
equalto,
864865
isimmutable,
865866
isless,
866867
ifelse,

base/file.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ function tempname(temppath::AbstractString,uunique::UInt32)
271271
tempp = cwstring(temppath)
272272
tname = Vector{UInt16}(32767)
273273
uunique = ccall(:GetTempFileNameW,stdcall,UInt32,(Ptr{UInt16},Ptr{UInt16},UInt32,Ptr{UInt16}), tempp,temp_prefix,uunique,tname)
274-
lentname = findfirst(tname,0)-1
274+
lentname = findfirst(iszero,tname)-1
275275
if uunique == 0 || lentname <= 0
276276
error("GetTempFileName failed: $(Libc.FormatMessage())")
277277
end

0 commit comments

Comments
 (0)