Delete element in an array for julia
Asked Answered
E

6

32

I've been wandering for a while in the docs and in forums and I haven't found a built in method/function to do the simple task of deleting an element in an array. Is there such built-in function?

I am asking for the equivalent of python's list.remove(x).

Here's an example of naively picking a function from the box:

julia> a=Any["D","A","s","t"]
julia> pop!(a, "s")
ERROR: MethodError: `pop!` has no method matching       
pop!(::Array{Any,1},     ::ASCIIString)
Closest candidates are:
  pop!(::Array{T,1})
  pop!(::ObjectIdDict, ::ANY, ::ANY)
  pop!(::ObjectIdDict, ::ANY)
  ...

Here mentions to use deleteat!, but also doesn't work:

julia> deleteat!(a, "s")
ERROR: MethodError: `-` has no method matching -(::Int64, ::Char)
Closest candidates are:
  -(::Int64)
  -(::Int64, ::Int64)
  -(::Real, ::Complex{T<:Real})
  ...

 in deleteat! at array.jl:621
Elinaelinor answered 9/2, 2016 at 17:52 Comment(0)
S
29

You can also go with filter!:

a = Any["D", "A", "s", "t"]
filter!(e->e≠"s",a)
println(a)

gives:

Any["D","A","t"]

This allows to delete several values at once, as in:

filter!(e->e∉["s","A"],a)

Note 1: In Julia 0.5, anonymous functions are much faster and the little penalty felt in 0.4 is not an issue anymore :-) .

Note 2: Code above uses unicode operators. With normal operators: is != and e∉[a,b] is !(e in [a,b])

Subvert answered 9/2, 2016 at 20:10 Comment(2)
This is the best solution. But for me the filter! doesn't work. Just filter is enough. So if I have Array b = ["s","A"] I can use as this filter(e->e∉b,a) which works great.Nik
A warning that filter! can be inefficient for large numbers of conditions or if you have to call it repeatedly. setdiff! is a better option if you know your collections are unique. And if you have a way to keep track of the indexes, you can delete with deleteat!() all at once.Cossack
S
12

Several of the other answers have been deprecated by more recent releases of Julia. I'm currently (Julia 1.1.0) using something like

function remove!(a, item)
    deleteat!(a, findall(x->x==item, a))
end

You can also use findfirst if you'd prefer, but it doesn't work if a does not contain item.

Sight answered 19/4, 2019 at 0:52 Comment(2)
Thanks for that! But it feels like the folks at Julia couldn't have made that more complicated if they tried.Cobber
If you use this in a critical loop, be warned that 99% of your resources may be using findall(). If you need this, maybe it would be better to keep an IdDict mapping the item to its index, then all you need to do is look up the index when you want to remove it.Cossack
G
9

Depending on the usage, it's also good to know setdiff and it's in-place version setdiff!:

julia> setdiff([1,2,3,4], [3])
3-element Array{Int64,1}:
 1
 2
 4

However, note that it also removes all repeated elements, as demonstrated in the example:

julia> setdiff!([1,2,3,4, 4], [3])
3-element Array{Int64,1}:
 1
 2
 4
Gibby answered 9/11, 2018 at 8:10 Comment(0)
G
2

You can use deleteat! and findall(compatible with Julia>1.0) for this.

a=Any["D","A","s","t","s"]
deleteat!(a, findall(x->x=="s",a))

Output:

3-element Array{Any,1}:
"D"
"A"
"t"
Gownsman answered 19/5, 2020 at 3:39 Comment(0)
M
1

I would add a note, deleteat!() can be used to delete an item from an array by its index:

julia>a = [1, 2, 3]
julia>deleteat(a, 3)
julia>display(a)
2-element Vector{Int64}:
 1
 2
Mccants answered 29/10, 2023 at 13:35 Comment(0)
C
0

The more recent answers are good. However, using a find___ function to look up the item to delete using deleteat!() is very inefficient. I found that my code using that took 100x longer than it needed to solely because I was using that method!

Another approach is to create a dictionary of the items and their indexes, so they can simply be looked up when necessary.

items # vector of items
itemindexes = IdDict(zip(items, eachindex(items))

todelete = Int[]

# do stuff and record indexes to delete with push!(todelete, <indexhere>)

sort!(todelete) # has to be in increasing order
deleteat!(items, todelete)

Obviously, once you use deleteat! the indexes become invalid so you'll need to update them.

Cossack answered 22/10, 2019 at 15:55 Comment(3)
A bit faster method, but a complete waste of time and effort coding. Especially when the Array has 1000 plus elements.Penance
Not a "complete waste of time and effort coding" if it's in a hot loop, Simon.Cossack
x_exp=deleteat!(x_exp,findall(u_exp[1:4] .< 0)); what about that for simple delete of elements whose indices have negative velocities from the first four elements.Penance

© 2022 - 2024 — McMap. All rights reserved.