Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

require explicit predicates in find functions #23812

Merged
merged 1 commit into from
Sep 29, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -297,6 +297,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
-----------------------------

@@ -489,6 +492,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
---------------------------

182 changes: 52 additions & 130 deletions base/array.jl
Original file line number Diff line number Diff line change
@@ -1599,14 +1599,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
@@ -1618,8 +1618,14 @@ julia> findnext(A,3)
function findnext(A, start::Integer)
l = endof(A)
i = start
warned = false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't this warn everytime the function is called?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was counting on depwarn for that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this looks good to me — the warned makes sure the slower depwarn is only called once for each invocation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, sorry for the noise.

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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I've done things like this I've often added breadcrumbs that point to it from deprecated.jl that help make sure they get removed at the appropriate timeframe.

Copy link
Contributor

@GregPlowman GregPlowman Oct 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should start be an argument to findnext in the depwarn message?

depwarn(" ... Use `findnext(x->x!=0, A, start)` instead.", :findnext)

Similarly for findprev?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, it should.

warned = true
end
if a != 0
return i
end
i = nextind(A, i)
@@ -1630,8 +1636,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
@@ -1649,58 +1656,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)
@@ -1750,21 +1705,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
@@ -1775,8 +1733,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
@@ -1785,8 +1749,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
@@ -1809,59 +1773,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)
@@ -1921,16 +1832,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}
```
@@ -1955,9 +1873,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
@@ -1971,7 +1888,7 @@ julia> find(A)
1
4
julia> find(zeros(3))
julia> find(falses(3))
0-element Array{Int64,1}
```
"""
@@ -1980,7 +1897,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
@@ -1989,7 +1911,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)
4 changes: 2 additions & 2 deletions base/combinatorics.jl
Original file line number Diff line number Diff line change
@@ -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
@@ -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
2 changes: 1 addition & 1 deletion base/datafmt.jl
Original file line number Diff line number Diff line change
@@ -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
8 changes: 8 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
@@ -1918,6 +1918,14 @@ end
@deprecate strwidth textwidth
@deprecate charwidth textwidth

@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
2 changes: 1 addition & 1 deletion base/event.jl
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
@@ -859,6 +859,7 @@ export
identity,
isbits,
isequal,
equalto,
isimmutable,
isless,
ifelse,
2 changes: 1 addition & 1 deletion base/file.jl
Original file line number Diff line number Diff line change
@@ -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
Loading