Easiest way to delete indices from Vector{Vector{}}

How to i obtain following

Input:
indices to delete

ind  = [2,4]

Vector of Vector

a  = [ [1.0,2,3,4,6,2], [10.0, 13, 4, 5, 2, 8] ]

Expected Output as below

2-element Vector{Vector{Float64}}:
 [1.0, 3.0, 6.0, 2.0]
 [10.0, 4.0, 2.0, 8.0]

For now, my implementation is by following way:

julia> [a[i][setdiff(1:length(a[i]), ind)] for i in 1:length(a)]
2-element Vector{Vector{Float64}}:
 [1.0, 3.0, 6.0, 2.0]
 [10.0, 4.0, 2.0, 8.0]



If mutation is fine

deleteat!.(a, Ref(ind))

otherwise

deleteat!.(copy.(a), Ref(ind))
4 Likes

Thanks ! That seems elegant :grinning:

Without the Ref() it appears that only a single element is removed from each element of a (and an error is raised if ind and a have different lengths). Why is the behavior different?

See Multi-dimensional Arrays · The Julia Language for documentation of broadcasting. Let’s consider a few simple cases of relevance here (and somewhat oversimplify how it works):

If f is a function, a a vector, and b a scalar, then the dot syntax

f.(a, b)

means

[f(a[i], b) for i in 1:length(a)]

If ‘b’ is instead a vector of length 1 it means

[f(a[i], b[1]) for i in 1:length(a)]

If b is a vector of length more than one it is indexed together with ‘a’

[f(a[i], b[i]) for i in 1:length(a)]

assuming that a and b have the same length, otherwise it’s an error.

For our deleteat! application we don’t want to index into ‘b’, which we can avoid by placing it in a container of size 1, e.g. [b] (single element vector) or (b,) (single element tuple)

f.(a, (b,))

which means

[f(a[i], (b,)[1]) for i in 1:length(a)]

or equivalently

[f(a[i], b) for i in 1:length(a)]

The use of Ref(b) is equivalent to (b,) in this context.

2 Likes

Just to note that in Julia, for-loop alternatives “never” hurt. Perhaps:

for v in a; deleteat!(v, ind); end
2 Likes