# Performance tips on turning arrays into tuples

**URL:** <https://discourse.julialang.org/t/performance-tips-on-turning-arrays-into-tuples/55586>\
**Category:** New to Julia\
**Created:** [February 18, 2021, 11:35pm UTC](https://discourse.julialang.org/t/performance-tips-on-turning-arrays-into-tuples/55586 "2021-02-18T23:35:19Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ribeiro](https://avatars.discourse-cdn.com/v4/letter/r/d9b06d/32.png) [@Ribeiro](https://discourse.julialang.org/u/Ribeiro)\
**Post date:** [February 18, 2021, 11:35pm UTC](https://discourse.julialang.org/t/performance-tips-on-turning-arrays-into-tuples/55586/1 "2021-02-18T23:35:19Z")

</div>

Hello,  
I have some Vectors of StaticArrays and I use them in functions like this:

```julia
fun(vec[1],vec[2],vec[3])

```

where each position of `vec` is a StaticArray.  
It would be helpful to do something like this:

```julia
fun(vec[1:3])
fun(vec[1:3]...,)

```

because I’m declaring these functions with 3 or 4 inputs. I notice a performance penalty from turning the vectors into a tuple (`...`) and from passing the 3 StaticArrays as a single vector.  
Is there a way to do this that is as fast as `fun(vec[1],vec[2],vec[3])`, but would let me pass 3 or 4 inputs to `fun`?  
The positions `1:3` are placeholders here. In reality, they are never consecutive and come from another vector of StaticArrays (`vec[indices[n][1]], vec[indices[n][2]], vec[indices[n][3]]` or `vec[indices[n]]`, to have them grouped).  
Thanks a lot!

---

<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:** [February 18, 2021, 11:58pm UTC](https://discourse.julialang.org/t/performance-tips-on-turning-arrays-into-tuples/55586/2 "2021-02-18T23:58:23Z")

</div>

You could explicitly define two methods, one with 3 other with 4 input vectors. What happens with the fourth vector when the function is called with only 3?

If it is taken as zero you can do something like

```julia
fun(v1::T,v2::T,v3::T) where T = fun(v1,v2,v3,zero(T))

```

for example

---

<div class="post-metadata">

**Author:** ![oxinabox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oxinabox/32/206603_2.png) [@oxinabox](https://discourse.julialang.org/u/oxinabox)\
**Post date:** [February 19, 2021, 12:13am UTC](https://discourse.julialang.org/t/performance-tips-on-turning-arrays-into-tuples/55586/3 "2021-02-19T00:13:09Z")

</div>

`ntuple` tends to be able extremely fast in my experience.  
Disproportionately so.

For the most performance criticsl code, that I benchmark carefully, I often end up using `ntuple`

---

<div class="post-metadata">

**Author:** ![Ribeiro](https://avatars.discourse-cdn.com/v4/letter/r/d9b06d/32.png) [@Ribeiro](https://discourse.julialang.org/u/Ribeiro)\
**Post date:** [February 19, 2021, 8:55am UTC](https://discourse.julialang.org/t/performance-tips-on-turning-arrays-into-tuples/55586/4 "2021-02-19T08:55:17Z")

</div>

@lmiq I have done this. The question is how to call these functions without explicitly writing the 3 or 4 inputs in a performance efficient way. So far, `fun(vec[1],vec[2],vec[3])` is by far the fastest way that I could think of doing this (compared to the other options in my original post).

@oxinabox I can test that, but how do I use ntuple with arbitrary indices? I can do `ntuple(i -> vec[i], 3)` to get `vec[1:3]`, but how can I get `(vec[4], vec[8], vec[2])`?  
Thanks a lot!

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [February 19, 2021, 9:34am UTC](https://discourse.julialang.org/t/performance-tips-on-turning-arrays-into-tuples/55586/5 "2021-02-19T09:34:16Z")

</div>

> [@Ribeiro](#):
>
> but how can I get `(vec[4], vec[8], vec[2])` ?

`ntuple(i->vec[indices[i]], length(indices))`

---

<div class="post-metadata">

**Author:** ![Ribeiro](https://avatars.discourse-cdn.com/v4/letter/r/d9b06d/32.png) [@Ribeiro](https://discourse.julialang.org/u/Ribeiro)\
**Post date:** [February 19, 2021, 9:51am UTC](https://discourse.julialang.org/t/performance-tips-on-turning-arrays-into-tuples/55586/6 "2021-02-19T09:51:39Z")

</div>

> [@Vasily\_Pisarev](#):
>
> ntuple(i-\>vec[indices[i]], length(indices))

Thanks a lot!  
@oxinabox `ntuple` is indeed very fast. I see almost no performance cost. Problem solved! Thanks a bunch!

---

<div class="post-metadata">

**Author:** ![oxinabox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oxinabox/32/206603_2.png) [@oxinabox](https://discourse.julialang.org/u/oxinabox)\
**Post date:** [February 19, 2021, 11:07am UTC](https://discourse.julialang.org/t/performance-tips-on-turning-arrays-into-tuples/55586/7 "2021-02-19T11:07:31Z")

</div>

I hate that it is so much faster than splatting.  
I think it is because it is generated and is easier to constant fold

---

<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:** [February 19, 2021, 11:53am UTC](https://discourse.julialang.org/t/performance-tips-on-turning-arrays-into-tuples/55586/8 "2021-02-19T11:53:29Z")

</div>

> [@Ribeiro](#):
>
> Problem solved!

I am missing something here. What is the final solutions?

> [@Vasily\_Pisarev](#):
>
> ntuple(i-\>vec[indices[i]], length(indices))

`vec[indices[i]]` allocates a new a vector, doesn’t it?

Even if that is faster than the splatting, it will not as fast a direct call like `fun(v1,v2,v3)`.

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [February 19, 2021, 1:05pm UTC](https://discourse.julialang.org/t/performance-tips-on-turning-arrays-into-tuples/55586/9 "2021-02-19T13:05:25Z")

</div>

> [@lmiq](#):
>
> `vec[indices[i]]` allocates a new a vector, doesn’t it?

Why it would? It is just two indexations: `indices[i]` and using its return to index `vec`. It would make sense that an anonymous function (`i->vec[indices[i]]`) is allocated but it is probably inlined.

---

<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:** [February 19, 2021, 1:11pm UTC](https://discourse.julialang.org/t/performance-tips-on-turning-arrays-into-tuples/55586/10 "2021-02-19T13:11:06Z")

</div>

> [@Henrique\_Becker](#):
>
> Why it would? It is just two indexations: `indices[i]`

I think I formulated wrongly the question. `indexes[i]` is necessarily a vector there, which has to be preallocated, meaning, that is something like

```julia
vec = [1,2,3,4,5]
indices = [2,3]
vec[indices]
#or
vec[[2,3] ]

```

Is there a syntax that allows that without allocating the intermediate `indices` vector?

---

<div class="post-metadata">

**Author:** ![Ribeiro](https://avatars.discourse-cdn.com/v4/letter/r/d9b06d/32.png) [@Ribeiro](https://discourse.julialang.org/u/Ribeiro)\
**Post date:** [February 19, 2021, 1:18pm UTC](https://discourse.julialang.org/t/performance-tips-on-turning-arrays-into-tuples/55586/11 "2021-02-19T13:18:25Z")

</div>

I don’t know why it’s fast, but it is. The compiler must be doing something fancy. When I try on a super simple cutdown, using `ntuple` is the same as `...,`, but inside of my function it works great!  
The syntax is so obtuse that VSCode highlights it as a possible error, though =P.

@lmiq I’m using `fun(ntuple(i->vec[indices[k][i]],3));`

Thanks again, everyone!

---

<div class="post-metadata">

**Author:** ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)\
**Post date:** [February 19, 2021, 7:40pm UTC](https://discourse.julialang.org/t/performance-tips-on-turning-arrays-into-tuples/55586/12 "2021-02-19T19:40:52Z")

</div>

Your problem seems closely related to

> [@Speeding Up Function with ::Function and ::Vararg input](https://discourse.julialang.org/t/speeding-up-function-with-function-and-vararg-input/55551):
>
> I need help understanding how/if I can speed up a function that has a ::Function argument and a ::Vararg argument. I have several functions that do almost the same thing. They each receive a few vector arguments, calculate some new vectors of the same size, then do some nested while looping to set the values of an output array. The looping part is almost identical across the different functions. The only difference is the function used to set the value of the output array inside the loops. So, …

I may misunderstand this, but the trick with the let block pointed out at the end of this thread may apply to your case as well.

---

<div class="post-metadata">

**Author:** ![healyp](https://avatars.discourse-cdn.com/v4/letter/h/67e7ee/32.png) [@healyp](https://discourse.julialang.org/u/healyp)\
**Post date:** [February 20, 2021, 4:47pm UTC](https://discourse.julialang.org/t/performance-tips-on-turning-arrays-into-tuples/55586/13 "2021-02-20T16:47:41Z")

</div>

> [@oxinabox](#):
>
> `ntuple` tends to be able extremely fast in my experience.  
> :  
> For the most performance criticsl code, that I benchmark carefully, I often end up using `ntuple`

Can you elaborate? Does the following contradict the above?

```julia
julia> const c=1000
1000

julia> @btime [2i for i in 1:c];
  864.123 ns (1 allocation: 7.94 KiB)

julia> @btime ntuple(i->2i, c);
  38.839 μs (751 allocations: 43.39 KiB)

```

Thanks.

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [February 20, 2021, 4:51pm UTC](https://discourse.julialang.org/t/performance-tips-on-turning-arrays-into-tuples/55586/14 "2021-02-20T16:51:16Z")

</div>

It is fast for lengths up to 16. Much beyond that, you shouldn’t really be using tuples anyways.

---

<div class="post-metadata">

**Author:** ![oxinabox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oxinabox/32/206603_2.png) [@oxinabox](https://discourse.julialang.org/u/oxinabox)\
**Post date:** [February 20, 2021, 6:21pm UTC](https://discourse.julialang.org/t/performance-tips-on-turning-arrays-into-tuples/55586/15 "2021-02-20T18:21:11Z")

</div>

Note that I said _“I benchmark carefully”_ and that for _“ **most** performance critical code I find `ntuple` fastest”_

There is no contradiction.

You too should benchmark carefully with something representative of your use case.

The two major cases I have were tuples that needed to correspond to fields of a struct, and tuples that corresponded to dimensions of an array.  
In both cases we are talking about much less than 10 elements.

Benchmarking is crucial when you are trying to put the last shine on something.

---

<div class="post-metadata">

**Author:** ![healyp](https://avatars.discourse-cdn.com/v4/letter/h/67e7ee/32.png) [@healyp](https://discourse.julialang.org/u/healyp)\
**Post date:** [February 20, 2021, 6:27pm UTC](https://discourse.julialang.org/t/performance-tips-on-turning-arrays-into-tuples/55586/16 "2021-02-20T18:27:07Z")

</div>

OK, fair point.

I wasn’t trying to take a cheap shot, just trying to understand.

Thanks.
