# Delete the nth frontal of a 3th-order tensor(array)

Consider the following tensor

``````A = reshape(1:24,4,2,3)
``````

I want to split it into two elements: B, which is the second frontal of A; and C, which is the remaining elements. Getting B is pretty obvious,

``````B = A[:,:,2]
``````

But I did not find a clever way to get C since functions such as `popat!()` and `deleteat!()` do not work for high-order arrays.

``````popat!(A, :, :, 2)

ERROR: MethodError: no method matching popat!(::Array{Int64, 3}, ::Colon, ::Colon, ::Int64)
Closest candidates are:
popat!(::Vector, ::Integer, ::Any) at /usr/share/julia/base/array.jl:1296
Stacktrace:
 top-level scope
@ REPL:1
``````

PS: For those who don’t know what a frontal is, here it is:

I just found the answer, I didn’t know that it is possible to select an element like that is julia

``````B = A[:,:,2]
C = A[:,:,1:end.!=2]
``````

you can also do:

``````using InvertedIndices
A[:, :, Not(2)]
``````
3 Likes

That is nice but is not built-in Nothing wrong with a small dependency. That’s why packages exist.

FWIW InvertedIndices.jl has no dependencies so it really is super light weight.

That is not the point. IMHO, the built-in solution solve it in a idiomatic way, making `InvertedIndices` unnecessary for this purpose. That is why I put my comment as solution.

`InvertedIndices` is also much slower than the builtin solution:

``````julia> A = rand(10, 10, 10);

julia> @btime \$A[:, :, (1:end) .!= 2];
1.457 μs (3 allocations: 7.28 KiB)
julia> @btime \$A[:, :, Not(2)];
4.558 μs (48 allocations: 8.62 KiB)

julia> A = rand(100, 100, 1000);

julia> @btime @view(\$A[:, :, (1:end) .!= 2]);
2.210 μs (4 allocations: 12.34 KiB)
julia> @btime @view(\$A[:, :, Not(2)]);
272.543 μs (5978 allocations: 179.41 KiB)
``````

Not sure if these performance issues are fundamental or can be improved.

1 Like

On my PC the following is even better:

``````@btime @view(\$A[:, :, [1;3:end]]);
``````

The drawback is that you cannot make it generic, while you can change `2` in `A[:, :, (1:end) .!= 2])` by a variable.

I think you can and it’s still faster:

``````n = 4
@btime @view(\$A[:, :, [1:(\$n-1);(\$n+1):end]]);
``````
2 Likes

Nice/Boa!

Below is a generalization that does not penalize the performance of the solution found by @rafael.guerra

``````n=[3,5,9]
@btime @view(\$A[:, :, deleteat!(collect(1:size(\$A,ndims(\$A))),\$n)]);
``````

here a function that takes advantage of the fact that the set of indices to be excluded is ordered.

``````@btime @view(\$A[:, :, notin(\$A,\$n)]);

function notin(A,n)
j=1
k=1
s=size(A,ndims(A))
sn=length(n)
nin=Vector{Int64}(undef, s-sn)
for i in 1:s
if i!=n[k]
nin[j]=i
j+=1
else
if k==sn
copyto!(nin,j,1:s,i+1,s-i)
break
else
k+=1
end
end
end
nin
end
``````

You should file an issue. I would expect `Not` to be faster.

There are unanswered performance issues already, likely related: Significant performance cost over naively filtering indices · Issue #14 · JuliaData/InvertedIndices.jl · GitHub and Bad performance caused by type unstable `iterate` · Issue #27 · JuliaData/InvertedIndices.jl · GitHub. I just assumed that performance isn’t a priority for InvertedIndices and so don’t use them myself (but wanted to).