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
Show file tree
Hide file tree
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
Expand Up @@ -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
-----------------------------

Expand Down Expand Up @@ -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
---------------------------

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

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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)

Expand Down Expand Up @@ -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}
```
Expand All @@ -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
Expand All @@ -1971,7 +1888,7 @@ julia> find(A)
1
4

julia> find(zeros(3))
julia> find(falses(3))
0-element Array{Int64,1}
```
"""
Expand All @@ -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
Expand All @@ -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)
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 @@ -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
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 @@ -859,6 +859,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