# In-place add to an array using duplicate indices

**URL:** <https://discourse.julialang.org/t/in-place-add-to-an-array-using-duplicate-indices/88464>\
**Category:** New to Julia\
**Created:** [October 9, 2022, 2:37am UTC](https://discourse.julialang.org/t/in-place-add-to-an-array-using-duplicate-indices/88464 "2022-10-09T02:37:10Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![cuihantao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cuihantao/32/8783_2.png) [@cuihantao](https://discourse.julialang.org/u/cuihantao)\
**Post date:** [October 9, 2022, 2:37am UTC](https://discourse.julialang.org/t/in-place-add-to-an-array-using-duplicate-indices/88464/1 "2022-10-09T02:37:10Z")

</div>

My code modifies an array in place using indices that contain duplicates. An MWE is as follows:

```julia
out = zeros(5)
mock_addr = [1, 1, 1, 1]
out[mock_addr] += [1, 2, 3, 4]
out

```

The result is `out = [4, 0, 0, 0, 0]`, which is the same as doing the same operation in Python using NumPy. NumPy provides `np.add.at(out, mock_addr, [1, 2, 3, 4])`, which yields my desired result of `out = [0, 10, 0, 0, 0]` (ignore the index shift).

Is there a similar function in Julia for the same functionality? I know one can write a for-loop, but I would like to keep the code concise.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [October 9, 2022, 3:26am UTC](https://discourse.julialang.org/t/in-place-add-to-an-array-using-duplicate-indices/88464/2 "2022-10-09T03:26:00Z")

</div>

```julia
for (i,v) in zip(mock_addr, [1,2,3,4])
    out[i] += v
end

```

---

<div class="post-metadata">

**Author:** ![cuihantao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cuihantao/32/8783_2.png) [@cuihantao](https://discourse.julialang.org/u/cuihantao)\
**Post date:** [October 9, 2022, 3:29am UTC](https://discourse.julialang.org/t/in-place-add-to-an-array-using-duplicate-indices/88464/3 "2022-10-09T03:29:12Z")

</div>

Thank you. I probably didn’t describe my question clearly. Is there any builtin function like `np.add.at` that does not require a for loop?

I use this operation on long expressions for multiple times, each on vectors of different sizes. I would rather not to use the for loop because a) eachindex need to be specified correctly, and b) the code would become less readable.

---

<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 9, 2022, 3:30am UTC](https://discourse.julialang.org/t/in-place-add-to-an-array-using-duplicate-indices/88464/4 "2022-10-09T03:30:29Z")

</div>

`@views out[mock_addr] .+= [1, 2, 3, 4]` gives you the desired result, but I’m not entirely sure whether this relies on it not noticing that the `view(out, mock_addr)` on the right aliases the one on the left. I think it fails on GPU arrays, which broadcast in parallel.

One function for this is:

```julia
NNlib.scatter!(+, zeros(5), [1,2,3,4.0], [1,1,1,1])

```

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [October 9, 2022, 3:31am UTC](https://discourse.julialang.org/t/in-place-add-to-an-array-using-duplicate-indices/88464/5 "2022-10-09T03:31:11Z")

</div>

> [@cuihantao](#):
>
> that does not require a for loop?

numpy functions are just loop in C.

> [@cuihantao](#):
>
> n long expressions for multiple times,

well just make your own function that runs faster than numpy (maybe, untested):

```julia
julia> function add_at(out, addrs, v) # this is for scalar v
           for i in addrs
               out[i] += v
           end
           return out
       end
add_at (generic function with 2 methods)

julia> function add_at(out, addrs, vals::AbstractArray)
           length(addrs) == length(vals) || error("unmatching length")
           for (i,v) in zip(addrs, vals)
               out[i] += v
           end
           return out
       end

```

---

<div class="post-metadata">

**Author:** ![cuihantao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cuihantao/32/8783_2.png) [@cuihantao](https://discourse.julialang.org/u/cuihantao)\
**Post date:** [October 9, 2022, 3:32am UTC](https://discourse.julialang.org/t/in-place-add-to-an-array-using-duplicate-indices/88464/6 "2022-10-09T03:32:06Z")

</div>

This is super interesting to know. Thank you.

---

<div class="post-metadata">

**Author:** ![cuihantao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cuihantao/32/8783_2.png) [@cuihantao](https://discourse.julialang.org/u/cuihantao)\
**Post date:** [October 9, 2022, 3:32am UTC](https://discourse.julialang.org/t/in-place-add-to-an-array-using-duplicate-indices/88464/7 "2022-10-09T03:32:39Z")

</div>

Thanks again! I will go with this approach.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [October 9, 2022, 3:34am UTC](https://discourse.julialang.org/t/in-place-add-to-an-array-using-duplicate-indices/88464/8 "2022-10-09T03:34:53Z")

</div>

does that one use simd scatter gather ?

---

<div class="post-metadata">

**Author:** ![cuihantao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cuihantao/32/8783_2.png) [@cuihantao](https://discourse.julialang.org/u/cuihantao)\
**Post date:** [October 9, 2022, 3:44am UTC](https://discourse.julialang.org/t/in-place-add-to-an-array-using-duplicate-indices/88464/9 "2022-10-09T03:44:23Z")

</div>

> [@mcabbott](#):
>
> @views out[mock\_addr] .+= [1, 2, 3, 4]

A note for others having a similar need:

To use the line above, both `@views` and the broadcast operation `.` are necessary. It won’t yield my desired result if either is missing.
