# How to improve performance in nested loops

**URL:** https://discourse.julialang.org/t/how-to-improve-performance-in-nested-loops/70407
**Category:** Performance
**Tags:** question, performance
**Created:** [October 26, 2021, 2:14pm UTC](https://discourse.julialang.org/t/how-to-improve-performance-in-nested-loops/70407 "2021-10-26T14:14:43Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![claudio20497](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/claudio20497/32/36602_2.png) [@claudio20497](https://discourse.julialang.org/u/claudio20497)
#### Post date: [October 26, 2021, 2:14pm UTC](https://discourse.julialang.org/t/how-to-improve-performance-in-nested-loops/70407/1 "2021-10-26T14:14:43Z")

</div>

Hello,

I’m writing a function whose performance suffers because of a nested for-loop. Below is a simplified version of that function.

The function `f()` takes no arguments, and instantiates `vecvec` a vector of vectors of `Int64`, all of the same size. Then, looping from `i = 1` to `5`, for each element of `vecvec` an operation that involves a slice of that element, the `i` index and a random component is performed. If the result of such operation is positive, the result is added to the element of `vecvec`, else the element must be removed from `vecvec`.

Here is the code:

```julia
function f()

    vecvec::Vector{Vector{Int64}} = [collect(i:(i+10)) for i in 1:10000]
    to_be_removed = Set{Int64}()

    for i in 1:5

        for (j,arr) in enumerate(vecvec)

            diff::Int64 = rand(Int64) + sum(arr[i:i+5]) - i
            diff>0 ? push!(arr,diff) : push!(to_be_removed,j)

        end

        vecvec = [arr for (k,arr) in enumerate(vecvec) if k ∉ to_be_removed]
        empty!(to_be_removed)

    end

    return vecvec

end

```

Current performance is:

```julia
julia> using BenchmarkTools
julia> @btime f();
  1.600 ms (33882 allocations: 5.39 MiB)

```

Would you know any way to make it faster ?

## Improvements

- @lmiq 's [suggestion](https://discourse.julialang.org/t/how-to-improve-performance-in-nested-loops/70407/2) helped bring it down to:

```julia
julia> @btime f();
  1.096 ms (14871 allocations: 3.07 MiB)

```

- @mcabbott 's [suggestion](https://discourse.julialang.org/t/how-to-improve-performance-in-nested-loops/70407/3), that I interpreted this way:

```julia
function f()

    vecvec::Matrix{Int64} = hcat([collect(i:(i+10)) for i in 1:10000]...)

    to_be_kept = Int64[]
    new_row = Int64[]
    

    for i in 1:5
        for (j,arr) in enumerate(eachcol(vecvec))

            diff::Int64 = rand(Int64) + sum(@view(arr[i:i+5])) - i

            if diff > 0
                push!(new_row,diff)
                push!(to_be_kept,j)
            end

        end
        vecvec = [@view(vecvec[:,to_be_kept]) ; new_row']
        empty!(to_be_kept)
        empty!(new_row)
    end

    return vecvec

end

```

Leads to:

```julia
julia> @btime new_f();
  1.062 ms (10065 allocations: 3.90 MiB)

```

---

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [October 26, 2021, 2:36pm UTC](https://discourse.julialang.org/t/how-to-improve-performance-in-nested-loops/70407/2 "2021-10-26T14:36:49Z")

</div>

> [@claudio20497](#):
>
> `sum(arr[i:i+5])`

use a view here: `sum(@view(arr[i:i+r]))`.

try to remove all allocations which are not completely on purpose.

---

<div class="post-metadata">

### Author: ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)
#### Post date: [October 26, 2021, 2:46pm UTC](https://discourse.julialang.org/t/how-to-improve-performance-in-nested-loops/70407/3 "2021-10-26T14:46:49Z")

</div>

Can you avoid having a vector of vectors, and resizing half of them? Perhaps if these are columns of a matrix, and you keep track of which to keep, and what to append, then at the end you can make a new matrix which has one more row.

---

<div class="post-metadata">

### Author: ![simsurace](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simsurace/32/30216_2.png) [@simsurace](https://discourse.julialang.org/u/simsurace)
#### Post date: [October 26, 2021, 10:34pm UTC](https://discourse.julialang.org/t/how-to-improve-performance-in-nested-loops/70407/4 "2021-10-26T22:34:50Z")

</div>

This is about three times faster on my system:

```julia
function g!(vec, i)
    sum = 0
    length(vec) >= i + 5 && @inbounds for i0 in 1:6
        sum += vec[i0+i-1]
    end
    diff = rand(Int) + sum - i
    push!(vec, diff)
end

mapg!(vecvec, i) = map(vec -> g!(vec, i), vecvec)

function G!(vecvec)
    for i in 1:5
        mapg!(vecvec, i)
        filter!(vec -> last(vec) <= 0, vecvec)
    end
    return vecvec
end

function f()
    vecvec = [collect(i:(i+10)) for i in 1:10000]
    G!(vecvec)
    return vecvec
end

```
