# Iterating over cols, vcat, repeat?

**URL:** <https://discourse.julialang.org/t/iterating-over-cols-vcat-repeat/15659>\
**Category:** Performance\
**Created:** [September 29, 2018, 10:18am UTC](https://discourse.julialang.org/t/iterating-over-cols-vcat-repeat/15659 "2018-09-29T10:18:16Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![qsong](https://avatars.discourse-cdn.com/v4/letter/q/d07c76/32.png) [@qsong](https://discourse.julialang.org/u/qsong)\
**Post date:** [September 29, 2018, 10:18am UTC](https://discourse.julialang.org/t/iterating-over-cols-vcat-repeat/15659/1 "2018-09-29T10:18:16Z")

</div>

I come from R world here for performance. @time shows that (123.55 k allocations: 6.260 MiB) for the below code. It seems more allocations than my expectation. So I was wondering if there be some improvement with the code?

```julia
m = reshape(1:12, 3, :);
map([m[:, i] for i = 1:size(m, 2)]) do x
    vcat(repeat(x, 1, 2), zeros(Int, 1, 2))
end

```

More specifically, two sub-questions below:

- were iterating over columns [m[:, i] for i = 1:size(m, 2)] expensive? The thread [https://github.com/JuliaLang/julia/issues/14491](https://github.com/JuliaLang/julia/issues/14491) has not been closed yet.
- were `vcat` or/and `repeat` expensive? if so, any suggestions for improvement? Thanks!

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [September 29, 2018, 10:51am UTC](https://discourse.julialang.org/t/iterating-over-cols-vcat-repeat/15659/2 "2018-09-29T10:51:14Z")

</div>

> [@qsong](#):
>
> m = reshape(1:12, 3, :); map([m[:, i] for i = 1:size(m, 2)]) do x vcat(repeat(x, 1, 2), zeros(Int, 1, 2)) end

You are benchmarking in global scope, try this

```julia
julia> m = reshape(1:12, 3, :);

julia> @time map([m[:, i] for i = 1:size(m, 2)]) do x
       vcat(repeat(x, 1, 2), zeros(Int, 1, 2))
       end
  0.088479 seconds (123.55 k allocations: 6.259 MiB)
4-element Array{Array{Int64,2},1}:
 [1 1; 2 2; 3 3; 0 0]      
 [4 4; 5 5; 6 6; 0 0]      
 [7 7; 8 8; 9 9; 0 0]      
 [10 10; 11 11; 12 12; 0 0]

julia> function f()
           m = reshape(1:12, 3, :);
           map([m[:, i] for i = 1:size(m, 2)]) do x
           vcat(repeat(x, 1, 2), zeros(Int, 1, 2))
           end
       end
f (generic function with 1 method)

julia> using BenchmarkTools

julia> @btime f()
  929.750 ns (23 allocations: 2.23 KiB)

```

The [manual](https://docs.julialang.org/en/v1/manual/performance-tips/index.html) tells you all you need to know about benchmarking and performance.

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [September 29, 2018, 12:17pm UTC](https://discourse.julialang.org/t/iterating-over-cols-vcat-repeat/15659/3 "2018-09-29T12:17:15Z")

</div>

If you are worried about allocations, you can reduce them further by

```julia
julia> function f()
           m = reshape(1:12, 3, :);
           map(@view(m[:, i]) for i = 1:size(m, 2)) do x
           vcat(repeat(x, 1, 2), zeros(Int, 1, 2))
           end
       end
f (generic function with 1 method)

julia> using BenchmarkTools

julia> @btime f()
  800.585 ns (17 allocations: 1.67 KiB)

```

The changes are

- Generator instead of comprehension as argument to `map`, this avoids the allocation of the vector.
- Use of `@view` to avoid allocating the slice `m[:, i]`

---

<div class="post-metadata">

**Author:** ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)\
**Post date:** [September 30, 2018, 5:18am UTC](https://discourse.julialang.org/t/iterating-over-cols-vcat-repeat/15659/4 "2018-09-30T05:18:23Z")

</div>

For optimal peformance, consider a devectorized solution:

```julia
function f()
    m = reshape(1:12, 3, :)
    p,q = size(m)
    A = Vector{Matrix{Int64}}(undef, q)
    @inbounds for i = 1:q
        A[i] = Matrix{Int64}(undef, p+1, 2)
        for k = 1:p
            A[i][k,1] = A[i][k,2] = m[k,i]
        end
        A[i][p+1,1] = A[i][p+1,2] = 0
    end
    A
end

julia> @btime f()
  172.140 ns (5 allocations: 688 bytes)

```

---

<div class="post-metadata">

**Author:** ![qsong](https://avatars.discourse-cdn.com/v4/letter/q/d07c76/32.png) [@qsong](https://discourse.julialang.org/u/qsong)\
**Post date:** [October 1, 2018, 11:56pm UTC](https://discourse.julialang.org/t/iterating-over-cols-vcat-repeat/15659/5 "2018-10-01T23:56:05Z")

</div>

Many thanks for all the help. Testing the built-in function `repeat` along the “devectorized” way and found that:

```julia
                                                                                                                                                                                     
julia> @btime repeat(1:5, 2, 3);                                                                                                                                                     
  121.025 ns (1 allocation: 336 bytes)                                                                                                                                               
                                                                                                                                                                                     
julia> @btime v = Vector{Int}(undef, 30); for i=1:5:30; v[i:(i+4)] = 1:5; end; reshape(v, 10, 3);                                                                                    
  34.007 ns (1 allocation: 336 bytes) 

```

Well, could I conclude that better avoiding built-in vectorized array functions for optimal performance in Julia? Thanks!

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [October 2, 2018, 12:11am UTC](https://discourse.julialang.org/t/iterating-over-cols-vcat-repeat/15659/6 "2018-10-02T00:11:16Z")

</div>

> [@qsong](#):
>
> @btime v = Vector{Int}(undef, 30); for i=1:5:30; v[i:(i+4)] = 1:5; end; reshape(v, 10, 3);

This doesn’t do what you think. You’re only benchmarking `v = Vector{Int}(undef, 30)`, and then running the remaining lines _after_ the benchmark is finished. The semicolon ends the expression, and so only the part before the first semicolon is picked up by `@btime`.

Try running it in a new Julia session to see that it actually errors when trying to reference `v` after the benchmark completes:

```julia
julia> @btime v = Vector{Int}(undef, 30); for i=1:5:30; v[i:(i+4)] = 1:5; end; reshape(v, 10, 3);
  27.772 ns (1 allocation: 336 bytes)
ERROR: UndefVarError: v not defined
Stacktrace:
 [1] top-level scope at ./REPL[23]:1 [inlined]
 [2] top-level scope at ./none:0

```

---

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [October 2, 2018, 12:21am UTC](https://discourse.julialang.org/t/iterating-over-cols-vcat-repeat/15659/7 "2018-10-02T00:21:09Z")

</div>

And note that you don’t necessarily have to squeeze everything onto one line; you can use `begin/end` instead to create a [compound expression](https://docs.julialang.org/en/v1/manual/control-flow/#man-compound-expressions-1).

```julia
@btime begin
    v = Vector{Int}(undef, 30)
    for i=1:5:30
        v[i:(i+4)] = 1:5
    end
    reshape(v, 10, 3)
end

```

---

<div class="post-metadata">

**Author:** ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)\
**Post date:** [October 2, 2018, 8:23am UTC](https://discourse.julialang.org/t/iterating-over-cols-vcat-repeat/15659/8 "2018-10-02T08:23:38Z")

</div>

My advice: Don’t worry so much about performance at the initial stage of your project. Instead try to make your code as readable and flexible as possible. That typically means using the built-in functions over devectorized code. During development, add plenty of unit tests for your code. Once your project is nearing completion, profile the code, _with production-sized input data_, to see where the bottlenecks are. Then optimize _those parts only_. Your unit tests will make sure that you don’t mess anything up while refactoring your code.

In my experience, with enough work, you can usually speed up code by devectorizing it, but in practice there is rarely a need to do so. Either the speedup is negligible, the part you’re optimizing is not a bottleneck, or the built-in function does such a good job that it’s not worth the effort and added complexity in your code to try to beat it.
