# Copy array elements by index

**URL:** <https://discourse.julialang.org/t/copy-array-elements-by-index/99127>\
**Category:** Performance\
**Tags:** question, performance, array\
**Created:** [May 19, 2023, 5:34pm UTC](https://discourse.julialang.org/t/copy-array-elements-by-index/99127 "2023-05-19T17:34:06Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Simon\_Exner](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simon_exner/32/50064_2.png) [@Simon\_Exner](https://discourse.julialang.org/u/Simon_Exner)\
**Post date:** [May 19, 2023, 5:34pm UTC](https://discourse.julialang.org/t/copy-array-elements-by-index/99127/1 "2023-05-19T17:34:06Z")

</div>

Hi,  
MWE:

```julia
function y_from_x!(y, x)
    interesting_indices = [7, 2, 4]
    for i in keys(interesting_indices)
        y[i] = x[interesting_indices[i]]
    end
end
a=collect(2:9)
b=zeros(3)
y_from_x!(b,a)

```

then b is [8.0,3.0,5.0] as expected

I would like to write this cleaner and more importantly with better performance (for bigger “interesting\_indices”, x and y vectors)  
I already found y[:] = getindex(x, interesting\_indices), but getindex allocates a new array, right? that would be bad performancewise, right?  
Any ideas?  
Also: would it be better to make the interesting\_indices a const? they wont change…  
Thanks

---

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [May 19, 2023, 5:46pm UTC](https://discourse.julialang.org/t/copy-array-elements-by-index/99127/2 "2023-05-19T17:46:09Z")

</div>

Welcome to Discourse!

I don’t think you can really improve the performance of this much from where you are, short of not allocating the `interesting_indices` array every call. For example, you could use a tuple `interesting_indices = (7,2,4)` to not allocate.

You are correct that `getindex` allocates a new array when called for an array of indices. But you can use [broadcasting](https://julialang.org/blog/2017/01/moredots/) over `getindex` to perform it all in terms of scalar `getindex` (which does not allocate):

```julia
y .= getindex.(Ref(x), interesting_indices)

```

Broadcasting is not _intrinsically_ faster than a loop, but it does tend to avoid excess boundschecks that might otherwise might happen if you aren’t careful in writing the loop.

---

<div class="post-metadata">

**Author:** ![barucden](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/barucden/32/26154_2.png) [@barucden](https://discourse.julialang.org/u/barucden)\
**Post date:** [May 19, 2023, 5:52pm UTC](https://discourse.julialang.org/t/copy-array-elements-by-index/99127/3 "2023-05-19T17:52:10Z")

</div>

Let me add some timings:

```julia
a = collect(2:9);
b = zeros(3);
I = [7, 2, 4]

function f!(y, x, i)
    y[:] = x[i]
end

function g!(y, x, i)
    @views y[:] = x[i]
end

function h!(y, x, i)
    y .= @view x[i]
end

julia> @btime f!($b, $a, $I)
  63.545 ns (1 allocation: 80 bytes)
julia> @btime g!($b, $a, $I)
  29.778 ns (0 allocations: 0 bytes)
julia> @btime h!($b, $a, $I)
  26.773 ns (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![Simon\_Exner](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simon_exner/32/50064_2.png) [@Simon\_Exner](https://discourse.julialang.org/u/Simon_Exner)\
**Post date:** [May 19, 2023, 6:00pm UTC](https://discourse.julialang.org/t/copy-array-elements-by-index/99127/4 "2023-05-19T18:00:56Z")

</div>

cool, thanks!  
so i guess with

```julia
const interesting_indices = [7,2,4]

function y_from_x!(y, x)
    y .= @view x[interesting_indices]
end

```

I will get the best performance and clean code. Thanks to the two of you!

---

<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:** [May 19, 2023, 7:42pm UTC](https://discourse.julialang.org/t/copy-array-elements-by-index/99127/5 "2023-05-19T19:42:27Z")

</div>

Having `interesting_indexes` as a global variable may limit your flexibility and/or performance. Maybe you just need to pass this array as a parameter. Also you can write that in one line, if you want it to be concise:

```julia
y_from_x!(x,y,interesting_indexes) = y .= @view x[interesting_indexes]

```

If you have to create `y` for every new set of interesting indexes, than the fastest way to do it is something like:

```julia
y_from_x!(x,y,interesting_indexes) = y .= @view x[interesting_indexes]

function y_from_x(x,interesting_indexes)
    y = similar(x, length(interesting_indexes))
    return y_from_x!(x,y,interesting_indexes)
end
```

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [May 20, 2023, 3:03pm UTC](https://discourse.julialang.org/t/copy-array-elements-by-index/99127/6 "2023-05-20T15:03:13Z")

</div>

I don’t know if clear enough, but very efficient.  
it can be even more so if the index vector is made up of consecutive index blocks

```julia
foreach(e->copyto!(b,e, a,I[e], 1), eachindex(b))

```
