Skip to content

Commit 25ce69f

Browse files
committed
require explicit predicates in find functions
fix #23120, fix #19186
1 parent 674e64b commit 25ce69f

28 files changed

+169
-191
lines changed

NEWS.md

+9
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,9 @@ Library improvements
292292

293293
* REPL Undo via Ctrl-/ and Ctrl-_
294294

295+
* New function `equalto(x)`, which returns a function that compares its argument to `x`
296+
using `isequal` ([#23812]).
297+
295298
Compiler/Runtime improvements
296299
-----------------------------
297300

@@ -484,6 +487,12 @@ Deprecated or removed
484487
* The timing functions `tic`, `toc`, and `toq` are deprecated in favor of `@time` and `@elapsed`
485488
([#17046]).
486489

490+
* Methods of `findfirst`, `findnext`, `findlast`, and `findprev` that accept a value to
491+
search for are deprecated in favor of passing a predicate ([#19186], [#10593]).
492+
493+
* `find` functions now operate only on booleans by default. To look for non-zeros, use
494+
`x->x!=0` or `!iszero` ([#23120]).
495+
487496
Command-line option changes
488497
---------------------------
489498

base/array.jl

+52-130
Original file line numberDiff line numberDiff line change
@@ -1599,14 +1599,14 @@ cat(n::Integer, x::Integer...) = reshape([x...], (ntuple(x->1, n-1)..., length(x
15991599
"""
16001600
findnext(A, i::Integer)
16011601
1602-
Find the next linear index >= `i` of a non-zero element of `A`, or `0` if not found.
1602+
Find the next linear index >= `i` of a `true` element of `A`, or `0` if not found.
16031603
16041604
# Examples
16051605
```jldoctest
1606-
julia> A = [0 0; 1 0]
1607-
2×2 Array{Int64,2}:
1608-
0 0
1609-
1 0
1606+
julia> A = [false false; true false]
1607+
2×2 Array{Bool,2}:
1608+
false false
1609+
true false
16101610
16111611
julia> findnext(A,1)
16121612
2
@@ -1618,8 +1618,14 @@ julia> findnext(A,3)
16181618
function findnext(A, start::Integer)
16191619
l = endof(A)
16201620
i = start
1621+
warned = false
16211622
while i <= l
1622-
if A[i] != 0
1623+
a = A[i]
1624+
if !warned && !(a isa Bool)
1625+
depwarn("In the future `findnext` will only work on boolean collections. Use `findnext(x->x!=0, A)` instead.", :findnext)
1626+
warned = true
1627+
end
1628+
if a != 0
16231629
return i
16241630
end
16251631
i = nextind(A, i)
@@ -1630,8 +1636,9 @@ end
16301636
"""
16311637
findfirst(A)
16321638
1633-
Return the linear index of the first non-zero value in `A` (determined by `A[i]!=0`).
1639+
Return the linear index of the first `true` value in `A`.
16341640
Returns `0` if no such value is found.
1641+
To search for other kinds of values, pass a predicate as the first argument.
16351642
16361643
# Examples
16371644
```jldoctest
@@ -1649,58 +1656,6 @@ julia> findfirst(zeros(3))
16491656
"""
16501657
findfirst(A) = findnext(A, 1)
16511658

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

17571715
"""
17581716
findprev(A, i::Integer)
17591717
1760-
Find the previous linear index <= `i` of a non-zero element of `A`, or `0` if not found.
1718+
Find the previous linear index <= `i` of a `true` element of `A`, or `0` if not found.
17611719
17621720
# Examples
17631721
```jldoctest
1764-
julia> A = [0 0; 1 2]
1765-
2×2 Array{Int64,2}:
1766-
0 0
1767-
1 2
1722+
julia> A = [false false; true true]
1723+
2×2 Array{Bool,2}:
1724+
false false
1725+
true true
17681726
17691727
julia> findprev(A,2)
17701728
2
@@ -1775,8 +1733,14 @@ julia> findprev(A,1)
17751733
"""
17761734
function findprev(A, start::Integer)
17771735
i = start
1736+
warned = false
17781737
while i >= 1
1779-
A[i] != 0 && return i
1738+
a = A[i]
1739+
if !warned && !(a isa Bool)
1740+
depwarn("In the future `findprev` will only work on boolean collections. Use `findprev(x->x!=0, A)` instead.", :findprev)
1741+
warned = true
1742+
end
1743+
a != 0 && return i
17801744
i = prevind(A, i)
17811745
end
17821746
return 0
@@ -1785,8 +1749,8 @@ end
17851749
"""
17861750
findlast(A)
17871751
1788-
Return the linear index of the last non-zero value in `A` (determined by `A[i]!=0`).
1789-
Returns `0` if there is no non-zero value in `A`.
1752+
Return the linear index of the last `true` value in `A`.
1753+
Returns `0` if there is no `true` value in `A`.
17901754
17911755
# Examples
17921756
```jldoctest
@@ -1809,59 +1773,6 @@ julia> findlast(A)
18091773
"""
18101774
findlast(A) = findprev(A, endof(A))
18111775

1812-
"""
1813-
findprev(A, v, i::Integer)
1814-
1815-
Find the previous linear index <= `i` of an element of `A` equal to `v` (using `==`), or `0` if not found.
1816-
1817-
# Examples
1818-
```jldoctest
1819-
julia> A = [0 0; 1 2]
1820-
2×2 Array{Int64,2}:
1821-
0 0
1822-
1 2
1823-
1824-
julia> findprev(A, 1, 4)
1825-
2
1826-
1827-
julia> findprev(A, 1, 1)
1828-
0
1829-
```
1830-
"""
1831-
function findprev(A, v, start::Integer)
1832-
i = start
1833-
while i >= 1
1834-
A[i] == v && return i
1835-
i = prevind(A, i)
1836-
end
1837-
return 0
1838-
end
1839-
1840-
"""
1841-
findlast(A, v)
1842-
1843-
Return the linear index of the last element equal to `v` in `A`.
1844-
Returns `0` if there is no element of `A` equal to `v`.
1845-
1846-
# Examples
1847-
```jldoctest
1848-
julia> A = [1 2; 2 1]
1849-
2×2 Array{Int64,2}:
1850-
1 2
1851-
2 1
1852-
1853-
julia> findlast(A,1)
1854-
4
1855-
1856-
julia> findlast(A,2)
1857-
3
1858-
1859-
julia> findlast(A,3)
1860-
0
1861-
```
1862-
"""
1863-
findlast(A, v) = findprev(A, v, endof(A))
1864-
18651776
"""
18661777
findprev(predicate::Function, A, i::Integer)
18671778
@@ -1921,16 +1832,23 @@ If there are no such elements of `A`, find returns an empty array.
19211832
19221833
# Examples
19231834
```jldoctest
1924-
julia> A = [1 2; 3 4]
1925-
2 Array{Int64,2}:
1926-
1 2
1927-
3 4
1835+
julia> A = [1 2 0; 3 4 0]
1836+
3 Array{Int64,2}:
1837+
1 2 0
1838+
3 4 0
19281839
1929-
julia> find(isodd,A)
1840+
julia> find(isodd, A)
19301841
2-element Array{Int64,1}:
19311842
1
19321843
2
19331844
1845+
julia> find(!iszero, A)
1846+
4-element Array{Int64,1}:
1847+
1
1848+
2
1849+
3
1850+
4
1851+
19341852
julia> find(isodd, [2, 4])
19351853
0-element Array{Int64,1}
19361854
```
@@ -1955,9 +1873,8 @@ _index_remapper(iter) = OneTo(typemax(Int)) # safe for objects that don't imple
19551873
"""
19561874
find(A)
19571875
1958-
Return a vector of the linear indexes of the non-zeros in `A` (determined by `A[i]!=0`). A
1959-
common use of this is to convert a boolean array to an array of indexes of the `true`
1960-
elements. If there are no non-zero elements of `A`, `find` returns an empty array.
1876+
Return a vector of the linear indices of the `true` values in `A`.
1877+
To search for other kinds of values, pass a predicate as the first argument.
19611878
19621879
# Examples
19631880
```jldoctest
@@ -1971,7 +1888,7 @@ julia> find(A)
19711888
1
19721889
4
19731890
1974-
julia> find(zeros(3))
1891+
julia> find(falses(3))
19751892
0-element Array{Int64,1}
19761893
```
19771894
"""
@@ -1980,7 +1897,12 @@ function find(A)
19801897
I = Vector{Int}(nnzA)
19811898
cnt = 1
19821899
inds = _index_remapper(A)
1900+
warned = false
19831901
for (i,a) in enumerate(A)
1902+
if !warned && !(a isa Bool)
1903+
depwarn("In the future `find(A)` will only work on boolean collections. Use `find(x->x!=0, A)` instead.", :find)
1904+
warned = true
1905+
end
19841906
if a != 0
19851907
I[cnt] = inds[i]
19861908
cnt += 1
@@ -1989,7 +1911,7 @@ function find(A)
19891911
return I
19901912
end
19911913

1992-
find(x::Number) = x == 0 ? Array{Int,1}(0) : [1]
1914+
find(x::Bool) = x ? [1] : Array{Int,1}(0)
19931915
find(testf::Function, x::Number) = !testf(x) ? Array{Int,1}(0) : [1]
19941916

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

base/combinatorics.jl

+2-2
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

+1-1
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

+8
Original file line numberDiff line numberDiff line change
@@ -1918,6 +1918,14 @@ end
19181918
@deprecate strwidth textwidth
19191919
@deprecate charwidth textwidth
19201920

1921+
@deprecate find(x::Number) find(!iszero, x)
1922+
@deprecate findnext(A, v, i::Integer) findnext(equalto(v), A, i)
1923+
@deprecate findfirst(A, v) findfirst(equalto(v), A)
1924+
@deprecate findprev(A, v, i::Integer) findprev(equalto(v), A, i)
1925+
@deprecate findlast(A, v) findlast(equalto(v), A)
1926+
# also remove deprecation warnings in find* functions in array.jl, sparse/sparsematrix.jl,
1927+
# and sparse/sparsevector.jl.
1928+
19211929
# END 0.7 deprecations
19221930

19231931
# BEGIN 1.0 deprecations

base/event.jl

+1-1
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

+1
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,7 @@ export
859859
identity,
860860
isbits,
861861
isequal,
862+
equalto,
862863
isimmutable,
863864
isless,
864865
ifelse,

base/file.jl

+1-1
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)