Julia BoundsError在迭代时删除列表中的项目

时间:2018-05-11 17:55:06

标签: julia

我想迭代列表并偶尔删除所述列表的项目。在玩具示例下面:

function delete_item!(myarray, item)
    deleteat!(myarray, findin(myarray, [item]))
end

n = 1000
myarray = [i for i = 1:n];

for a in myarray
    if a%2 == 0
        delete_item!(myarray, a)
    end
end

然而我收到错误:

BoundsError: attempt to access 500-element Array{Int64,1} at index [502]

如何解决(尽可能高效)?

其他信息。以上看起来似乎是一个愚蠢的例子,在我原来的问题中,我有一个代理商列表进行交互。因此,我不确定迭代副本是否是最佳解决方案。例如:

#creating my agent
mutable struct agent <: Any
    id::Int
end

function delete_item!(myarray::Array{agent, 1}, item::agent)
    deleteat!(myarray, findin(myarray, [item]))
end 

#having my list of agents
n = 1000
myarray = agent[agent(i) for i = 1:n];

#trying to remove agents from list while having them interact
for a in myarray
    #agent does stuff
    if a.id%2 == 0 #if something happens remove
        delete_item!(myarray, a)
    end
end

1 个答案:

答案 0 :(得分:3)

不幸的是,这个问题没有单一答案,因为最有效的方法取决于整个模型的逻辑(特别是其他代理的操作取决于某些条目实际上是从数组中删除的事实)。

在大多数情况下,以下方法应该是最简单的(我要离开findin这是低效的,但我知道你可能在myarray中通常会有重复项:

n = 1000
myarray = [i for i = 1:n];
keep = trues(n)

for (i, a) in enumerate(myarray)
    keep[i] || continue # do not process an agent that is marked for deletion
    if a%2 == 0 # here application logic might also need to check keep in some cases
        keep[findin(myarray, [a])] = false
    end
end

myarray = myarray[keep]

如果由于某种原因你真的需要在每次迭代中删除myarray的元素,那么你将如何做到这一点:

n = 1000
myarray = [i for i = 1:n];

i = 1
while i <= length(myarray)
    a = myarray[i]
    if a%2 == 0
        todelete = findin(myarray, [a])
        i -= count(x -> x < i, todelete) # if myarray has duplicates of a you have to move the counter back
        deleteat!(myarray, todelete)
    else
        i += 1
    end
end

一般情况下,您提供的代码不会非常快(例如,如果您知道myarray不包含重复项,则可以更加简单 - 我想您可以这样做。)

编辑:如果您知道没有重复项,可以使用以下方法实现这两个版本(您只需使用代理的索引 - 请注意我们也可以避免不必要的检查):

n = 1000
myarray = [i for i = 1:n];
keep = trues(n)

for (i, a) in enumerate(myarray)
    if a%2 == 0 # here application logic might also need to check keep in some cases
        keep[i] = false
    end
end

myarray = myarray[keep]

如果由于某种原因你真的需要在每次迭代中删除myarray的元素,那么你将如何做到这一点:

n = 1000
myarray = [i for i = 1:n];

i = 1
while i <= length(myarray)
    a = myarray[i]
    if a%2 == 0
        deleteat!(myarray, i)
    else
        i += 1
    end
end