Skip to content

Commit

Permalink
require explicit predicates in find functions
Browse files Browse the repository at this point in the history
fix #23120, fix #19186
  • Loading branch information
JeffBezanson committed Sep 22, 2017
1 parent ff9fb48 commit 1eb0827
Show file tree
Hide file tree
Showing 28 changed files with 158 additions and 191 deletions.
9 changes: 9 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,9 @@ Library improvements

* REPL Undo via Ctrl-/ and Ctrl-_

* New function `equalto(x)`, which returns a function that compares its argument to `x`
using `isequal` ([#23812]).

Compiler/Runtime improvements
-----------------------------

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

* Methods of `findfirst`, `findnext`, `findlast`, and `findprev` that accept a value to
search for are deprecated in favor of passing a predicate ([#19186], [#10593]).

* `find` functions now operate only on booleans by default. To look for non-zeros, use
`x->x!=0` or `!iszero` ([#23120]).

Command-line option changes
---------------------------

Expand Down
182 changes: 52 additions & 130 deletions base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1596,14 +1596,14 @@ cat(n::Integer, x::Integer...) = reshape([x...], (ntuple(x->1, n-1)..., length(x
"""
findnext(A, i::Integer)
Find the next linear index >= `i` of a non-zero element of `A`, or `0` if not found.
Find the next linear index >= `i` of a `true` element of `A`, or `0` if not found.
# Examples
```jldoctest
julia> A = [0 0; 1 0]
2×2 Array{Int64,2}:
0 0
1 0
julia> A = [false false; true false]
2×2 Array{Bool,2}:
false false
true false
julia> findnext(A,1)
2
Expand All @@ -1615,8 +1615,14 @@ julia> findnext(A,3)
function findnext(A, start::Integer)
l = endof(A)
i = start
warned = false
while i <= l
if A[i] != 0
a = A[i]
if !warned && !(a isa Bool)
depwarn("In the future `findnext` will only work on boolean collections. Use `findnext(x->x!=0, A)` instead.", :findnext)
warned = true
end
if a != 0
return i
end
i = nextind(A, i)
Expand All @@ -1627,8 +1633,9 @@ end
"""
findfirst(A)
Return the linear index of the first non-zero value in `A` (determined by `A[i]!=0`).
Return the linear index of the first `true` value in `A`.
Returns `0` if no such value is found.
To search for other kinds of values, pass a predicate as the first argument.
# Examples
```jldoctest
Expand All @@ -1646,58 +1653,6 @@ julia> findfirst(zeros(3))
"""
findfirst(A) = findnext(A, 1)

"""
findnext(A, v, i::Integer)
Find the next linear index >= `i` of an element of `A` equal to `v` (using `==`), or `0` if not found.
# Examples
```jldoctest
julia> A = [1 4; 2 2]
2×2 Array{Int64,2}:
1 4
2 2
julia> findnext(A,4,4)
0
julia> findnext(A,4,3)
3
```
"""
function findnext(A, v, start::Integer)
l = endof(A)
i = start
while i <= l
if A[i] == v
return i
end
i = nextind(A, i)
end
return 0
end
"""
findfirst(A, v)
Return the linear index of the first element equal to `v` in `A`.
Returns `0` if `v` is not found.
# Examples
```jldoctest
julia> A = [4 6; 2 2]
2×2 Array{Int64,2}:
4 6
2 2
julia> findfirst(A,2)
2
julia> findfirst(A,3)
0
```
"""
findfirst(A, v) = findnext(A, v, 1)

"""
findnext(predicate::Function, A, i::Integer)
Expand Down Expand Up @@ -1747,21 +1702,24 @@ julia> findfirst(iseven, A)
julia> findfirst(x -> x>10, A)
0
julia> findfirst(equalto(4), A)
3
```
"""
findfirst(testf::Function, A) = findnext(testf, A, 1)

"""
findprev(A, i::Integer)
Find the previous linear index <= `i` of a non-zero element of `A`, or `0` if not found.
Find the previous linear index <= `i` of a `true` element of `A`, or `0` if not found.
# Examples
```jldoctest
julia> A = [0 0; 1 2]
2×2 Array{Int64,2}:
0 0
1 2
julia> A = [false false; true true]
2×2 Array{Bool,2}:
false false
true true
julia> findprev(A,2)
2
Expand All @@ -1772,8 +1730,14 @@ julia> findprev(A,1)
"""
function findprev(A, start::Integer)
i = start
warned = false
while i >= 1
A[i] != 0 && return i
a = A[i]
if !warned && !(a isa Bool)
depwarn("In the future `findprev` will only work on boolean collections. Use `findprev(x->x!=0, A)` instead.", :findprev)
warned = true
end
a != 0 && return i
i = prevind(A, i)
end
return 0
Expand All @@ -1782,8 +1746,8 @@ end
"""
findlast(A)
Return the linear index of the last non-zero value in `A` (determined by `A[i]!=0`).
Returns `0` if there is no non-zero value in `A`.
Return the linear index of the last `true` value in `A`.
Returns `0` if there is no `true` value in `A`.
# Examples
```jldoctest
Expand All @@ -1806,59 +1770,6 @@ julia> findlast(A)
"""
findlast(A) = findprev(A, endof(A))

"""
findprev(A, v, i::Integer)
Find the previous linear index <= `i` of an element of `A` equal to `v` (using `==`), or `0` if not found.
# Examples
```jldoctest
julia> A = [0 0; 1 2]
2×2 Array{Int64,2}:
0 0
1 2
julia> findprev(A, 1, 4)
2
julia> findprev(A, 1, 1)
0
```
"""
function findprev(A, v, start::Integer)
i = start
while i >= 1
A[i] == v && return i
i = prevind(A, i)
end
return 0
end

"""
findlast(A, v)
Return the linear index of the last element equal to `v` in `A`.
Returns `0` if there is no element of `A` equal to `v`.
# Examples
```jldoctest
julia> A = [1 2; 2 1]
2×2 Array{Int64,2}:
1 2
2 1
julia> findlast(A,1)
4
julia> findlast(A,2)
3
julia> findlast(A,3)
0
```
"""
findlast(A, v) = findprev(A, v, endof(A))

"""
findprev(predicate::Function, A, i::Integer)
Expand Down Expand Up @@ -1918,16 +1829,23 @@ If there are no such elements of `A`, find returns an empty array.
# Examples
```jldoctest
julia> A = [1 2; 3 4]
2 Array{Int64,2}:
1 2
3 4
julia> A = [1 2 0; 3 4 0]
3 Array{Int64,2}:
1 2 0
3 4 0
julia> find(isodd,A)
julia> find(isodd, A)
2-element Array{Int64,1}:
1
2
julia> find(!iszero, A)
4-element Array{Int64,1}:
1
2
3
4
julia> find(isodd, [2, 4])
0-element Array{Int64,1}
```
Expand All @@ -1952,9 +1870,8 @@ _index_remapper(iter) = OneTo(typemax(Int)) # safe for objects that don't imple
"""
find(A)
Return a vector of the linear indexes of the non-zeros in `A` (determined by `A[i]!=0`). A
common use of this is to convert a boolean array to an array of indexes of the `true`
elements. If there are no non-zero elements of `A`, `find` returns an empty array.
Return a vector of the linear indices of the `true` values in `A`.
To search for other kinds of values, pass a predicate as the first argument.
# Examples
```jldoctest
Expand All @@ -1968,7 +1885,7 @@ julia> find(A)
1
4
julia> find(zeros(3))
julia> find(falses(3))
0-element Array{Int64,1}
```
"""
Expand All @@ -1977,7 +1894,12 @@ function find(A)
I = Vector{Int}(nnzA)
cnt = 1
inds = _index_remapper(A)
warned = false
for (i,a) in enumerate(A)
if !warned && !(a isa Bool)
depwarn("In the future `find(A)` will only work on boolean collections. Use `find(x->x!=0, A)` instead.", :find)
warned = true
end
if a != 0
I[cnt] = inds[i]
cnt += 1
Expand All @@ -1986,7 +1908,7 @@ function find(A)
return I
end

find(x::Number) = x == 0 ? Array{Int,1}(0) : [1]
find(x::Bool) = x ? [1] : Array{Int,1}(0)
find(testf::Function, x::Number) = !testf(x) ? Array{Int,1}(0) : [1]

findn(A::AbstractVector) = find(A)
Expand Down
4 changes: 2 additions & 2 deletions base/combinatorics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ function permute!!(a, p::AbstractVector{<:Integer})
count = 0
start = 0
while count < length(a)
ptr = start = findnext(p, start+1)
ptr = start = findnext(!iszero, p, start+1)
temp = a[start]
next = p[start]
count += 1
Expand Down Expand Up @@ -125,7 +125,7 @@ function ipermute!!(a, p::AbstractVector{<:Integer})
count = 0
start = 0
while count < length(a)
start = findnext(p, start+1)
start = findnext(!iszero, p, start+1)
temp = a[start]
next = p[start]
count += 1
Expand Down
2 changes: 1 addition & 1 deletion base/datafmt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ function val_opts(opts)
for (opt_name, opt_val) in opts
in(opt_name, valid_opts) ||
throw(ArgumentError("unknown option $opt_name"))
opt_typ = valid_opt_types[findfirst(valid_opts, opt_name)]
opt_typ = valid_opt_types[findfirst(equalto(opt_name), valid_opts)]
isa(opt_val, opt_typ) ||
throw(ArgumentError("$opt_name should be of type $opt_typ, got $(typeof(opt_val))"))
d[opt_name] = opt_val
Expand Down
8 changes: 8 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1855,6 +1855,14 @@ end
nothing
end

@deprecate find(x::Number) find(!iszero, x)
@deprecate findnext(A, v, i::Integer) findnext(equalto(v), A, i)
@deprecate findfirst(A, v) findfirst(equalto(v), A)
@deprecate findprev(A, v, i::Integer) findprev(equalto(v), A, i)
@deprecate findlast(A, v) findlast(equalto(v), A)
# also remove deprecation warnings in find* functions in array.jl, sparse/sparsematrix.jl,
# and sparse/sparsevector.jl.

# END 0.7 deprecations

# BEGIN 1.0 deprecations
Expand Down
2 changes: 1 addition & 1 deletion base/event.jl
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ function ensure_rescheduled(othertask::Task)
# if the current task was queued,
# also need to return it to the runnable state
# before throwing an error
i = findfirst(Workqueue, ct)
i = findfirst(t->t===ct, Workqueue)
i == 0 || deleteat!(Workqueue, i)
ct.state = :runnable
end
Expand Down
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,7 @@ export
identity,
isbits,
isequal,
equalto,
isimmutable,
isless,
ifelse,
Expand Down
2 changes: 1 addition & 1 deletion base/file.jl
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ function tempname(temppath::AbstractString,uunique::UInt32)
tempp = cwstring(temppath)
tname = Vector{UInt16}(32767)
uunique = ccall(:GetTempFileNameW,stdcall,UInt32,(Ptr{UInt16},Ptr{UInt16},UInt32,Ptr{UInt16}), tempp,temp_prefix,uunique,tname)
lentname = findfirst(tname,0)-1
lentname = findfirst(iszero,tname)-1
if uunique == 0 || lentname <= 0
error("GetTempFileName failed: $(Libc.FormatMessage())")
end
Expand Down
Loading

0 comments on commit 1eb0827

Please sign in to comment.