# Sum or fold over fields in a struct

**URL:** <https://discourse.julialang.org/t/sum-or-fold-over-fields-in-a-struct/57901>\
**Category:** New to Julia\
**Tags:** question\
**Created:** [March 24, 2021, 11:38pm UTC](https://discourse.julialang.org/t/sum-or-fold-over-fields-in-a-struct/57901 "2021-03-24T23:38:23Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Anticrisis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/anticrisis/32/21745_2.png) [@Anticrisis](https://discourse.julialang.org/u/Anticrisis)\
**Post date:** [March 24, 2021, 11:38pm UTC](https://discourse.julialang.org/t/sum-or-fold-over-fields-in-a-struct/57901/1 "2021-03-24T23:38:23Z")

</div>

Given an array of RGB{UInt8} values, how can we collect the sums of their independent :r, :g, and :b 8-bit components, without overflowing?

We can write a `for` loop and do this manually:

```julia
for v in arr
   r += v.r
   g += v.g
   b += v.b
end

```

We can use the `sum` function:

```julia
r = sum(v -> v.r, arr)
g = sum(v -> v.g, arr)
b = sum(v -> v.b, arr)

```

but this is likely to be much less efficient than the for loop, because it has to iterate three times, correct?

If we write:

```julia
rgbsum = sum(arr)

```

we overflow if arr is an array of RGB structs with 8-bit fields.

Is there a way to ask the `sum` function to accumulate its sum into an RGB{Float64}, for example, so that `rgbsum = sum(arr)` would work without overflow and as efficiently as the explicit `for` loop?

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [March 25, 2021, 12:02am UTC](https://discourse.julialang.org/t/sum-or-fold-over-fields-in-a-struct/57901/2 "2021-03-25T00:02:47Z")

</div>

Not sure which RGB type we are talking about (it doesn’t seem to be the one from Colors.jl) but you could try something like:

```julia
foldl(+, arr; init=RGB{Float64}(0.0,0.0,0.0))

```

That is fold/reduce the array via addition with a `RGB{Float64}` initial value.

Example with a simple fake RGB type:

```julia
julia> struct RGB{T}
           r::T
           g::T
           b::T
       end

julia> Base.:+(x::RGB, y::RGB) = RGB(x.r + y.r, x.g + y.g, x.b + y.b)

julia> arr = RGB{UInt8}.(rand(UInt8,10), rand(UInt8,10), rand(UInt8,10));

julia> typeof(arr)
Array{RGB{UInt8},1}

julia> foldl(+, arr; init=RGB{Float64}(0,0,0))
RGB{Float64}(894.0, 1321.0, 1086.0)

```

---

<div class="post-metadata">

**Author:** ![thisrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thisrod/32/10642_2.png) [@thisrod](https://discourse.julialang.org/u/thisrod)\
**Post date:** [March 25, 2021, 12:07am UTC](https://discourse.julialang.org/t/sum-or-fold-over-fields-in-a-struct/57901/3 "2021-03-25T00:07:00Z")

</div>

Another option, maybe a bit clearer, would be a typecast in `sum`:

```
sum(RGB{UInt16}, arr)

```

But yes, it would help if the example code included the `using` statement that imported the `RGB` type.

---

<div class="post-metadata">

**Author:** ![Anticrisis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/anticrisis/32/21745_2.png) [@Anticrisis](https://discourse.julialang.org/u/Anticrisis)\
**Post date:** [March 25, 2021, 12:59am UTC](https://discourse.julialang.org/t/sum-or-fold-over-fields-in-a-struct/57901/4 "2021-03-25T00:59:34Z")

</div>

Ah, thank you. The `init` argument was what I needed.

---

<div class="post-metadata">

**Author:** ![Anticrisis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/anticrisis/32/21745_2.png) [@Anticrisis](https://discourse.julialang.org/u/Anticrisis)\
**Post date:** [March 25, 2021, 1:06am UTC](https://discourse.julialang.org/t/sum-or-fold-over-fields-in-a-struct/57901/5 "2021-03-25T01:06:24Z")

</div>

I’m sorry for the type confusion. This RGB type comes from the Images package, but I was intending to ask a more general question, which you’ve both answered.

I like the typecast approach of `sum(RGB{Float64}, arr)`, but it seems to perform much worse than the `foldl(+, arr, init=RGB{Float64}(0,0,0))` approach. 20ms vs 0.25ms for an array of size (460, 374).

---

<div class="post-metadata">

**Author:** ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)\
**Post date:** [March 25, 2021, 1:28am UTC](https://discourse.julialang.org/t/sum-or-fold-over-fields-in-a-struct/57901/6 "2021-03-25T01:28:34Z")

</div>

It’ll be faster to retain the underlying `UInt` representation using a `N24f8` or similar instead of doing a floating-point conversion:

```julia
julia> using BenchmarkTools, Images

julia> arr = rand(RGB{N0f8}, 460, 374);

julia> @btime foldl(+, $arr; init=RGB{Float64}(0, 0, 0))
  158.500 μs (0 allocations: 0 bytes)
RGB{Float64}(86118.69411764605,85819.37254901891,86040.69019608037)

julia> @btime foldl(+, $arr; init=RGB{N24f8}(0, 0, 0))
  29.900 μs (0 allocations: 0 bytes)
RGB{N24f8}(86118.7,85819.4,86040.7)

```

This is only an option if you know the sum for each channel will be less than `typemax(N24f8)`

```julia
julia> typemax(N24f8) |> Float64
1.6843009e7

```

…but you can get around this with `N56f8` if need be:

```julia
julia> @btime foldl(+, $arr; init=RGB{N56f8}(0, 0, 0))
  54.800 μs (78 allocations: 2.73 KiB)
RGB{N56f8}(86118.7,85819.4,86040.7)

```

---

<div class="post-metadata">

**Author:** ![thisrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thisrod/32/10642_2.png) [@thisrod](https://discourse.julialang.org/u/thisrod)\
**Post date:** [March 25, 2021, 3:26am UTC](https://discourse.julialang.org/t/sum-or-fold-over-fields-in-a-struct/57901/7 "2021-03-25T03:26:23Z")

</div>

> [@Anticrisis](#):
>
> I like the typecast approach of `sum(RGB{Float64}, arr)` , but it seems to perform much worse than the `foldl(+, arr, init=RGB{Float64}(0,0,0))` approach.

That’s worth raising as an issue, unless the difference is compilation time or something like that. Could you please post a complete example, either here or on Github, with the code you ran that printed those times?

---

<div class="post-metadata">

**Author:** ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)\
**Post date:** [March 25, 2021, 3:41am UTC](https://discourse.julialang.org/t/sum-or-fold-over-fields-in-a-struct/57901/8 "2021-03-25T03:41:18Z")

</div>

At least on v1.6, it’s actually faster than the `foldl` approach:

```julia
julia> @btime sum(RGB{Float64}, $arr)
  76.800 μs (0 allocations: 0 bytes)
RGB{Float64}(86118.69411764707,85819.37254901961,86040.69019607845)

```

\*\*edit: can confirm that it’s much slower on v1.5.

```julia
julia> @btime sum(RGB{Float64}, $arr)
  17.857 ms (516119 allocations: 13.13 MiB)

```
