Remove iterator in loop

question

#1

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.


#2

Does using deleteat!(A, index) help?
Gotta watch out for shifting lengths and index acces though.


#3

or do you mean continue?


#4

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.


#5

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.


#6

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).

See http://docs.julialang.org/en/stable/manual/interfaces/


#7

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

#8

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.


#9

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 

#10

@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!


#11

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.


#12

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

#13

Excellent. Thanks. Even mere mortals such as myself can make sense out of that.


#14

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).


#15

I have came across a few myself. Evidently, this particular issue is documented on github.


#16

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


#17

Thanks for the lead. That sounds potentially relevant to my project.


#18

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.


#19

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 ?


#20

You’re right; for some reason this function is not documented. My mistake.