2017-07-02 125 views
2

我的第一个尝试是:删除元素

I = Vector{String}(["first", "second", "third", "fourth"]) 

for i in I 
    if i == "fourth" 
     splice!(I, 4) 
    end 
    print("$i\n") 
end 

其在界失误结束:

BoundsError(String["first", "second", "third"], (5,)) 

后来我想通它有点了“手写”的方式:

I = Vector{String}(["first", "second", "third", "fourth"]) 

state = start(I) 

while ! done(I, state) 
    (i, state) = next(I, state) 

    if i == "fourth" 
     splice!(I, state - 1) 
     print("Delete element i=$(state - 1)\n") 
     state = state - 1 
     continue 
    end 

    print("Got: i=$i state=$state\n") 
end 

输出:

Got: i=first state=2 
Got: i=second state=3 
Got: i=third state=4 
Delete element i=4 

但是,是的,这既不容易阅读,也不容易写。是否有任何“朱利安”的方式来删除矢量元素,而迭代呢?或者是否有推荐的数据结构通过某种函数调用明确支持它?

+0

我不知道你想要什么,但'啪!(I) '接近你在找什么? [是的,我不知道这是否与菠菜有关。] – rickhg12hs

+0

@ rickhg12hs哈哈,不幸的是不是我所需要的。我需要能够从矢量中删除任何元素,而不管它在迭代时的位置。 – lama12345

回答

3

解决方法1:使用shift!push!

julia> I = Vector{String}(["first", "second", "third", "fourth", "fifth"]); 
julia> Inew = Vector{String}(0); 
julia> while !isempty(I) 
     i = shift!(I); 
     if i == "fourth"; println("Skipped $i"); 
     else println("Got: i = $i"); push!(Inew, i); 
     end 
     end 
Got: i = first 
Got: i = second 
Got: i = third 
Skipped fourth 
Got: i = fifth 

julia> show(Inew) 
String["first", "second", "third", "fifth"] 


解决方案2:使用splice!

julia> I = Vector{String}(["first", "second", "third", "fourth", "fifth"]); 
julia> i = 1; 
julia> while i <= length(I) 
     if I[i] == "fourth"; splice!(I,i); 
     else i += 1; 
     end 
     end 
julia> show(I) 
String["first", "second", "third", "fifth"] 

但是,请注意,这并不一定是更有效的,因为新内存分配为I只要你拼接它反正(因为它的尺寸正在改变)。


解决方案3:使用findindeleteat!(即 “一衬里”):

julia> I = Vector{String}(["first", "second", "third", "fourth", "fifth"]); 
julia> deleteat!(I, findin(I, ["second", "fourth"])) 
3-element Array{String,1}: 
"first" 
"third" 
"fifth" 

如果你真的不需要执行任何其他中间动作(例如打印),你只是想识别和删除元素,那么这可能是一条路。


进一步随笔:

此外,关于您尝试通过一个循环做到这一点:一个迭代的循环(在任何语言)时,基本规则是,国家你正在迭代的变量不会改变。违反这一规则通常会导致最佳情况下的错误,或最坏情况下的未定义行为和无声错误。如果变量的状态是要改变的,那么你就不是在寻找'for循环'迭代,而是在更一般的while循环中,它不会假设一致的状态。

即,你在这里所做的是正确的方法,你不应该寻找一个涉及for循环的方法。 (如果你碰巧找到一个,请考虑那些不好的代码,并保持独立:p)。但是,是的,有更好的方法来做到这一点。但值得注意的是,你所做的基本上是重新发现轮子,因为你明确了for循环实际上依赖于julia的界面。即下面的代码:

for i in MyCollection; print("$i "); end 

基本被内部转换为等值:

state = start(MyCollection) 
while !done(MyCollection, state) 
    (i, state) = next(MyCollection, state) 
    print("$i ") 
end 

+0

谢谢,你的第二种方式正是我所寻找的。容易在眼睛上,不会创建新的数组,并且只需在迭代它时简单地删除一个或多个元素。完美:) – lama12345

1

调用splice!多次为大型阵列很慢:

function d!(I, s) 
    i = 1 
    while i <= length(I) 
     if I[i] == s; splice!(I,i); 
     else i += 1; 
     end 
    end 
end 

function t() 
    I = rand(1:10, 1000000) 
    s = 1 
    d!(I,s) 
    I 
end 

julia> @btime t() 
6.752 s (2 allocations: 7.63 MiB) 
899975-element Array{Int64,1}: 
... 

最好是与产生应删除所有索引的迭代器,如调用deleteat!只有一次,

function d2!(I, s) 
    deleteat!(I, (i for i in eachindex(I) if I[i] == s)) 
end 

function t2() 
    I = rand(1:10, 1000000) 
    s = 1 
    d2!(I,s) 
    I 
end 

julia> @btime t2() 
15.889 ms (8 allocations: 7.63 MiB) 
900414-element Array{Int64,1}: 
...