Discussion:
[julia-users] Implementing an iterator which conditionally skips elements.
Kristoffer Carlsson
2015-05-01 19:07:03 UTC
Permalink
Hello everyone,

I have what is likely a basic question about iterators in Julia.

Let's say I want to implement an iterator over a vector of objects and only
return (or yield) the objects that have some sort property.

Initially I tried something like this:


immutable MyIter{T}
v::Vector{T}
end

Base.start() = 1
Base.done(::MyIter, state) = state > length(v)

function Base.next(myiter::MyIter, state)
if has_property(v[state])
return(v[state], state+1)
else
return(next(myiter, state+1))
end


This does not work because when I hit the last element with the property
the iterator will go into an infinite loop. It feels like I have to check
if there are any more elements
left with the property in the done function but then I have to iterate over
the rest of the vector...

What I basically want is in my next function to be able to say "No more
items to return, stop iterating". In Python I would just yield the value
when the property is true and raise StopIterating when I reach the end of
the vector. Can I do something similar in Julia?

Best regards,
Kristoffer Carlsson
ggggg
2015-05-01 19:27:39 UTC
Permalink
Maybe look at dict.jl?

https://github.com/JuliaLang/julia/blob/master/base/dict.jl

There is a definition like:
next(t::Dict, i) = ((t.keys[i],t.vals[i]), skip_deleted(t,i+1))

function skip_deleted(h::Dict, i) L = length(h.slots) while i<=L &&
!isslotfilled(h,i) i += 1 end return i end
Post by Kristoffer Carlsson
Hello everyone,
I have what is likely a basic question about iterators in Julia.
Let's say I want to implement an iterator over a vector of objects and
only return (or yield) the objects that have some sort property.
immutable MyIter{T}
v::Vector{T}
end
Base.start() = 1
Base.done(::MyIter, state) = state > length(v)
function Base.next(myiter::MyIter, state)
if has_property(v[state])
return(v[state], state+1)
else
return(next(myiter, state+1))
end
This does not work because when I hit the last element with the property
the iterator will go into an infinite loop. It feels like I have to check
if there are any more elements
left with the property in the done function but then I have to iterate
over the rest of the vector...
What I basically want is in my next function to be able to say "No more
items to return, stop iterating". In Python I would just yield the value
when the property is true and raise StopIterating when I reach the end of
the vector. Can I do something similar in Julia?
Best regards,
Kristoffer Carlsson
Steven G. Johnson
2015-05-01 20:26:38 UTC
Permalink
Post by Kristoffer Carlsson
Let's say I want to implement an iterator over a vector of objects and
only return (or yield) the objects that have some sort property.
What you're describing is the filter iterator, which is already implemented
in the Julia standard library. If you want to know how to do it, see:

https://github.com/JuliaLang/julia/blob/37041bb039b33dfe2ae02a6f17f8f9639df94c5d/base/iterator.jl#L58-L96

For example, Filter(iseven, A) returns an iterator over only the
even-valued elements of some array A of integers.
Kristoffer Carlsson
2015-05-01 22:11:26 UTC
Permalink
Thank you ggggg, that is very helpful and provided me with what I needed to
know. The key insight is to move the lookup of the next active element to
the state calculation like they did in what you linked.

Steven, thank you for the link to filter. I am not sure if I can use it
straight off the standard library because my use case is a bit more
complicated than I wrote in my original post. I tried doing something
similar to what filter is doing but right now it is too slow to be usable.
Since this is in a very tight loop I am guessing the tuple allocations are
dragging down the performance. I am currently on a pre tuple rework commit
so it might be better after I update.

Thanks for your help again, both of you.
Post by Steven G. Johnson
Post by Kristoffer Carlsson
Let's say I want to implement an iterator over a vector of objects and
only return (or yield) the objects that have some sort property.
What you're describing is the filter iterator, which is already
implemented in the Julia standard library. If you want to know how to do
https://github.com/JuliaLang/julia/blob/37041bb039b33dfe2ae02a6f17f8f9639df94c5d/base/iterator.jl#L58-L96
For example, Filter(iseven, A) returns an iterator over only the
even-valued elements of some array A of integers.
Loading...