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

findfirst and findnext for general iterables #15755

Closed
wants to merge 2 commits into from
Closed
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
2 changes: 2 additions & 0 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,8 @@ sub2ind(dims::Tuple{Vararg{Integer}}, I::Integer...) = _sub2ind(dims,I)
end
Expr(:block, meta,:($ex + 1))
end
sub2ind(A::AbstractArray, I::Integer...) = _sub2ind(size(A), I)
_sub2ind(A::AbstractArray, I) = _sub2ind(size(A), I)

@generated function ind2sub{N}(dims::NTuple{N,Integer}, ind::Integer)
meta = Expr(:meta,:inline)
Expand Down
16 changes: 10 additions & 6 deletions base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -727,15 +727,19 @@ end
findfirst(A) = findnext(A, 1)

# returns the index of the next matching element
function findnext(A, v, start::Integer)
for i = start:length(A)
if A[i] == v
return i
function findnext{T}(iter, v, state::T, failed::T)
while !done(iter, state)
oldstate = state
item, state = next(iter, state)
if item == v
return oldstate
end
end
return 0
return failed
end
findfirst(A, v) = findnext(A, v, 1)
findnext(iter, v, state::Integer) = findnext(iter, v, state, oftype(state, 0))

findfirst(iter, v) = findnext(iter, v, start(iter))

# returns the index of the next element for which the function returns true
function findnext(testf::Function, A, start::Integer)
Expand Down
4 changes: 2 additions & 2 deletions base/bitarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1295,7 +1295,7 @@ function findnext(B::BitArray, start::Integer)
end
return 0
end
#findfirst(B::BitArray) = findnext(B, 1) ## defined in array.jl
findfirst(B::BitArray) = findnext(B, 1)

# aux function: same as findnext(~B, start), but performed without temporaries
function findnextnot(B::BitArray, start::Integer)
Expand Down Expand Up @@ -1335,7 +1335,7 @@ function findnext(B::BitArray, v, start::Integer)
v == true && return findnext(B, start)
return 0
end
#findfirst(B::BitArray, v) = findnext(B, 1, v) ## defined in array.jl
findfirst(B::BitArray, v) = findnext(B, v, 1)

# returns the index of the first element for which the function returns true
function findnext(testf::Function, B::BitArray, start::Integer)
Expand Down
1 change: 0 additions & 1 deletion base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,6 @@ end
@deprecate flipud(A::AbstractArray) flipdim(A, 1)
@deprecate fliplr(A::AbstractArray) flipdim(A, 2)

@deprecate sub2ind{T<:Integer}(dims::Array{T}, sub::Array{T}) sub2ind(tuple(dims...), sub...)
@deprecate ind2sub!{T<:Integer}(sub::Array{T}, dims::Array{T}, ind::T) ind2sub!(sub, tuple(dims...), ind)

@deprecate strftime Libc.strftime
Expand Down
6 changes: 5 additions & 1 deletion base/multidimensional.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
### Multidimensional iterators
module IteratorsMD

import Base: eltype, length, size, start, done, next, last, getindex, setindex!, linearindexing, min, max, eachindex, ndims, iteratorsize
import Base: eltype, length, size, start, done, next, last, getindex, setindex!, linearindexing, min, max, eachindex, ndims, iteratorsize, sub2ind, _sub2ind
importall ..Base.Operators
import Base: simd_outer_range, simd_inner_length, simd_index, @generated
import Base: @nref, @ncall, @nif, @nexprs, LinearFast, LinearSlow, to_index, AbstractCartesianIndex
Expand Down Expand Up @@ -50,6 +50,10 @@ length{N}(::Type{CartesianIndex{N}})=N
# indexing
getindex(index::CartesianIndex, i::Integer) = index.I[i]

# conversion to linear index
sub2ind(A::AbstractArray, I::CartesianIndex) = _sub2ind(A, I.I)
_sub2ind(A::AbstractArray, I::CartesianIndex) = _sub2ind(A, I.I)

# arithmetic, min/max
for op in (:+, :-, :min, :max)
@eval begin
Expand Down
25 changes: 25 additions & 0 deletions base/nullable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,28 @@ function hash(x::Nullable, h::UInt)
return hash(x.value, h + nullablehash_seed)
end
end

## Methods that can't be defined until we have Nullable

function findnext{T}(iter, v, state::T, failed::Nullable{T})
while !done(iter, state)
oldstate = state
item, state = next(iter, state)
if item == v
return Nullable(oldstate)
end
end
return failed
end

findnext(iter, v, state) = findnext(iter, v, state, Nullable{typeof(state)}())

# For arrays, ensure findfirst returns an integer even for LinearSlow
_findnext(A::AbstractArray, v, state::Integer) = findnext(A, v, state, oftype(state, 0))
function _findnext(A::AbstractArray, v, state)
found = findnext(A, v, state)
isnull(found) && return 0
sub2ind(A, get(found)[2])
end

findfirst(A::AbstractArray, v) = _findnext(A, v, start(A))
8 changes: 8 additions & 0 deletions test/arrayops.jl
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ a = [0,1,2,3,0,1,2,3]
@test findnext(a,1) == 2
@test findnext(a,1,4) == 6
@test findnext(a,5,4) == 0
@test findnext(a,5,0x04) === 0x00
@test findlast(a) == 8
@test findlast(a.==0) == 5
@test findlast(a.==5) == 0
Expand All @@ -298,6 +299,13 @@ a = [0,1,2,3,0,1,2,3]
@test findprev(a,1,8) == 6
@test findprev(isodd, [2,4,5,3,9,2,0], 7) == 5
@test findprev(isodd, [2,4,5,3,9,2,0], 2) == 0
let A = reshape(1:20, 5, 4)
B = sub(A, 1:4, 1:3)
@test findfirst(B,8) == 7
@test findfirst(B,5) == 0
@test get(findnext(B,8,start(B)))[2] == CartesianIndex((3,2))
@test isnull(findnext(B,5,start(B)))
end

## findn ##

Expand Down
4 changes: 4 additions & 0 deletions test/strings/search.jl
Original file line number Diff line number Diff line change
Expand Up @@ -373,3 +373,7 @@ end
# string searchindex with a two-char UTF-8 (4 byte) string literal
@test rsearchindex("\U1f596\U1f596", "\U1f596\U1f596") == 1
@test rsearchindex("\U1f596\U1f596", "\U1f596\U1f596", endof("\U1f596\U1f596\U1f596")) == 1

# using findfirst (#15723)
@test findfirst("⨳(",'(') == 4
@test findfirst("⨳(",'x') == 0