2017-07-02 238 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}: 
...