Skip to content

Commit

Permalink
findnext and findfirst for general iterables (fixes #15723)
Browse files Browse the repository at this point in the history
  • Loading branch information
timholy committed Apr 3, 2016
1 parent ccaca30 commit 9000057
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 8 deletions.
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
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

0 comments on commit 9000057

Please sign in to comment.