# Dropdims but an order of magnitude faster

**URL:** <https://discourse.julialang.org/t/dropdims-but-an-order-of-magnitude-faster/142795>\
**Category:** Internals & Design\
**Tags:** performance, type-stability\
**Created:** [November 6, 2026, 5:36pm UTC](https://discourse.julialang.org/t/dropdims-but-an-order-of-magnitude-faster/142795 "2026-11-06T17:36:56Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![skraemer](https://avatars.discourse-cdn.com/v4/letter/s/4bbf92/32.png) [@skraemer](https://discourse.julialang.org/u/skraemer)\
**Post date:** [November 6, 2026, 5:36pm UTC](https://discourse.julialang.org/t/dropdims-but-an-order-of-magnitude-faster/142795/1 "2026-11-06T17:36:56Z")

</div>

The function `dropdims` uses the short but (intermediately) type-instable pattern

```julia
ax = _foldoneto((ds, d) -> d in dims ? ds : (ds..., axes(A,d)), (), Val(ndims(A)))
reshape(A, ax::typeof(_sub(axes(A), dims)))

```

Replacing this part with `dropinds` below, or basically anything reasonable avoiding length-of-tuple type instability, saves up to an order magnitude in time as well as allocations. As far as I can see it is equally compilation-heavy.

My guess is that `dropdims` has simply never been high priority, but maybe I am missing something.

If the point is code brevity, working explicitly with a vector instead is still better (see further below). Probably some kind of case destinction concerning `N` would be best.

```julia
function dropinds(::Val{N}, inds::NTuple{M,Int}) where {N,M}
    @assert allunique(inds) "inds = $inds does not have unique entries"
    @assert all(x->x in 1:N, inds) "inds = $inds not within 1:$N"
    _dropinds(Val(N), inds, 0)
end
function _dropinds(::Val{N}, inds::NTuple{M,Int}, k::Int) where {N,M}
    N == M && return tuple()
    while N-k in inds
        k = k+1
    end
    return (_dropinds(Val(N-1), inds, k+1)..., N-k)
end
function dropdims_by_dropinds(x::Array{T,N}, dims::Tuple{Vararg{Int}}) where {T,N}
    t = dropinds(Val(N), dims)
    new_s = map(i->axes(x, i), t)
    reshape(x, new_s)
end

```

```julia-auto
function test()
    a = randn(1, 2, 1, 1, 2, 1, 1)
    dims = Tuple(findall(==(1), size(a)))
    s = 0.0
    @time for i = 1:1000; s += dropdims_by_dropinds(a, dims)[1]; end
    @time for i = 1:1000; s += dropdims(a; dims)[1]; end

    a = randn(1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1)
    dims = Tuple(findall(==(1), size(a)))
    @time for i = 1:1000; s += dropdims_by_dropinds(a, dims)[1]; end
    @time for i = 1:1000; s += dropdims(a; dims)[1]; end
    return s
end
test()
# 0.000066 seconds (3.00 k allocations: 78.125 KiB)
# 0.000366 seconds (10.00 k allocations: 281.250 KiB)
# 0.000187 seconds (3.00 k allocations: 93.750 KiB)
# 0.001141 seconds (28.00 k allocations: 890.625 KiB)

```

Vector version:

```julia
function dropinds_vec(::Val{N}, inds::NTuple{M,Int}) where {N,M}
    @assert allunique(inds) "inds = $inds does not have unique entries"
    @assert all(x->x in 1:N, inds) "inds = $inds not within 1:$N"
    
    s = collect(1:N)
    for x = inds
        s[x] = N+1
    end
    w = 1
    for v = s
        s[w] = v
        w = ifelse(v == N+1, w, w+1)
    end  
    return ntuple(i->s[i], N-M)
end
function dropdims_by_dropinds_vec(x::Array{T,N}, dims::Tuple{Vararg{Int}}) where {T,N}
    t = dropinds_vec(Val(N), dims)
    new_s = map(i->axes(x, i), t)
    reshape(x, new_s)
end
function test()
    a = randn(1, 2, 1, 1, 2, 1, 1)
    dims = Tuple(findall(==(1), size(a)))
    s = 0.0
    @time for i = 1:1000; s += dropdims_by_dropinds_vec(a, dims)[1]; end
    @time for i = 1:1000; s += dropdims(a; dims)[1]; end

    a = randn(1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1)
    dims = Tuple(findall(==(1), size(a)))
    @time for i = 1:1000; s += dropdims_by_dropinds_vec(a, dims)[1]; end
    @time for i = 1:1000; s += dropdims(a; dims)[1]; end
    return s
end
test()
# 0.000089 seconds (5.00 k allocations: 187.500 KiB)
# 0.000508 seconds (10.00 k allocations: 281.250 KiB)
# 0.000188 seconds (5.00 k allocations: 328.125 KiB)
# 0.001286 seconds (28.00 k allocations: 890.625 KiB)

```
