I was wondering if there is a way to remove an iterator in a loop. For example,
for obj in Objects if someCondition removeIterator(obj) end do other stuff... end
There is a way to do this in Java.
I was wondering if there is a way to remove an iterator in a loop. For example,
for obj in Objects if someCondition removeIterator(obj) end do other stuff... end
There is a way to do this in Java.
Does using deleteat!(A, index)
help?
Gotta watch out for shifting lengths and index acces though.
or do you mean continue
?
Not sure exactly what you mean to do - you could use filter!
and then apply the other stuff?. If you don’t mind making a copy [x^2 for x in randn(10) if x > 0]
. EDIT: I guess these responses aren’t actually helpful, sorry.
Hi all. Thanks for the responses. As @miguelraz noted, deleting the object will cause a shift in length and throw off alignment because it doesn’t actually update the underlying indexing.
My simulation involves interacting agents in a game theoretic context. Some agents are removed from the game and therefore should not interact with other agents, and should not contribute to the decisions of the remaining agents. So if I delete the 5th agent when agent 3 is making a decision, an error happens on the next iteration because the agent iterator is not updated. One way to hand this is to use checks throughout (if agent.interacting == true), but thats a little cumbersome. So I would be interested in something similar to the solution in the Java link involving a safe/adaptive remove function.
Just write your own iterator.
for obj in ActiveAgentIterator(Objects)
and then you defined your ActiveAgentIterator
with suitable iterator interface functions (most special here will be the next
function that will look for the next active agent).
Thanks @kristoffer.carlsson. This looks like a very elegant solution. If it only iterates agents that are interacting, it greatly simplifies my code and book keeping.
I’m having trouble figuring out how to specify a condition in the next()
function. As you can see, what I tried does not skip over agent 5 even though it is set to false in the loop. Do you know how to do this? Thanks.
type Agent
id::Int
interacting::Bool
end
Base.start(::Agent) = 1
Base.next(S::Agent, state) = (Agent.interacting==true, state+1)
Base.done(S::Agent, state) = state > Agent.count
Base.eltype(::Type{Agent}) = Int
Base.length(S::Agent) = S.count
Agents = [Agent(i,true) for i = 1:10]
for agent in Agents
println([agent])
Agents[5].interacting = false
end
You are still just looping over a list of agents. You need a new type which wraps the array of agents and it is on this type you define the iterator interface. Please look at the link I posted earlier for some examples.
You have a bit of an awkward case here that is covered by this issue: https://github.com/JuliaLang/julia/issues/8149
Here is something that seems to work:
type Agent
id::Int
interacting::Bool
end
type InteractingAgentIterator
v::Vector{Agent}
index::Int
end
interacting(agents::AbstractArray{Agent}) = InteractingAgentIterator(agents, 0)
Base.eltype(::Type{InteractingAgentIterator}) = Agent
Base.start(::InteractingAgentIterator) = Void # state not used
function Base.next(A::InteractingAgentIterator, i)
return A.v[A.index], Void
end
function Base.done(A::InteractingAgentIterator, state)
A.index += 1
found_agent = false
while A.index <= length(A.v)
if A.v[A.index].interacting
found_agent = true
break
end
A.index += 1
end
return !found_agent
end
Testing it:
Agents = [Agent(i,true) for i = 1:10]
Agents[1].interacting = false
Agents[5].interacting = false
Agents[10].interacting = false
for agent in interacting(Agents)
println("I am agent ", agent.id, " and I am ", !agent.interacting ? "not " : "", "interacting")
end
Prints:
I am agent 2 and I am interacting
I am agent 3 and I am interacting
I am agent 4 and I am interacting
I am agent 6 and I am interacting
I am agent 7 and I am interacting
I am agent 8 and I am interacting
I am agent 9 and I am interacting
@kristoffer.carlsson Much appreciated. I did go through the link you sent to me, but couldn’t quite figure it out. I had no idea that the heavy lifting was in Base.done
. This should really simplify my code. Thanks again!
That’s the problem with the current iterator interface. If you have an iterator that you don’t know when it is done until you try, then you basically have to use the awkward way I showed.
Here is a solution using Filter
(which doesn’t appear to be documented)
type Agent
id::Int
interacting::Bool
end
agents = [Agent(i,true) for i = 1:10];
agents[1].interacting = false
agents[5].interacting = false
agents[10].interacting = false
for agent in Filter(x->x.interacting,agents)
println("I am agent ", agent.id, " and I am ", !agent.interacting ? "not " : "", "interacting")
end
Excellent. Thanks. Even mere mortals such as myself can make sense out of that.
Neat. There are surprisingly many undocumented gems in Julia still. The two solutions benchmark identically on my computer (I replaced the println with an array comprehension).
I have came across a few myself. Evidently, this particular issue is documented on github.
If you are interested, Jeff Bezanson’s PhD thesis (on his Github) has a section or two on an incrementally abstract agent iterator with the example of predatory-prey models.
@Christopher_Fisher: Found it. Section 3.3.1 - A Hierarchy of Dispatch
Thanks for the lead. That sounds potentially relevant to my project.
This is documented in 0.6 as Base.Iterators.filter
(Note lowercase f).
On 0.5 and 0.6 one should use Compat.Iterators.filter
instead of the undocumented implementation detail Filter
.
Sorry, I can’t find it - I would have thougt it could be found on this page: http://docs.julialang.org/en/latest/stdlib/iterators.html ?
You’re right; for some reason this function is not documented. My mistake.