删除元素
我的第一个尝试是:删除元素
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
但是,是的,这既不容易阅读,也不容易写。是否有任何“朱利安”的方式来删除矢量元素,而迭代呢?或者是否有推荐的数据结构通过某种函数调用明确支持它?
解决方法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:使用findin
和deleteat!
(即 “一衬里”):
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
谢谢,你的第二种方式正是我所寻找的。容易在眼睛上,不会创建新的数组,并且只需在迭代它时简单地删除一个或多个元素。完美:) – lama12345
调用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}:
...
我不知道你想要什么,但'啪!(I) '接近你在找什么? [是的,我不知道这是否与菠菜有关。] – rickhg12hs
@ rickhg12hs哈哈,不幸的是不是我所需要的。我需要能够从矢量中删除任何元素,而不管它在迭代时的位置。 – lama12345