Sum of empty list comprehension

I’m trying to convert some python code to julia

I have a construction something like:

sum([Lc[x] for x in somelist])

which fails when somelist is an empty array. The python version returns 0, as I want, for the sum.

What’s the “best” (fastest?) julia replacement here?
Is there any way to do this list comprehension and force the returned type to be e.g., Float64? That would have worked:
sum(zeros(Float64, 0)) = 0.0

The issue is what type of zero to return. For example, if you are summing a list of 3×3 matrices, you don’t want 0, you want a 3×3 matrix of zeros.

By default, it tries to get the type of zero from the element type of the array. However, [Lc[x] for x in []] returns an Any[] array, and Any provides no information about the type of zero. (See also https://github.com/JuliaLang/julia/issues/27766).

One possibility would be to simply give the array comprehension an explicit type, e.g.

sum(Float64[Lc[x] for x in somelist])

Another argument is to use reduce, which allows you to specify an explicit init argument:

reduce(+, [Lc[x] for x in somelist], init=0.0)

If you are trying to write type-generic code, that could be invoked for different types of Lc, then you need to be more careful and use eltype(Lc) so that your code is both type-stable and responsive to the types of the input.

Alternatively, you can simply do

sum(Lc[somelist])

where somelist is an array of indices (possibly empty), and it will do the right thing: you can index an array with another array to get a slice/subset.

1 Like

Thanks!

Of course the real code is more complex

Mji = [o for o in Mj if o != i]
Lq[l,j] = Lc[j]+sum(Float64[Lr[e,d[e,j]] for e in Mji])

where ‘d’ is a Dict, which prevents using your simple suggestion

sum(Lc[somelist])

I adopted your suggestion to give array comprehension a specific type, which is what I was looking for. Didn’t notice it in the docs.

Note that you could avoid allocating all of these temporary arrays. e.g. you can avoid the Float64[...] array with

Lq[l,j] = mapreduce(e -> Lr[e,d[e,j]], +, Mji, init=Lc[j])

I adopted your suggestion to give array comprehension a specific type, which is what I was looking for. Didn’t notice it in the docs.

This is mentioned at the end of the comprehensions section: Single- and multi-dimensional Arrays · The Julia Language

1 Like

You actually don’t need the comprehension here. Ditch the square brackets and let the sum function operate on a generator and you’ll save some allocations. This is not a solution to your empty list case, though.

A solution using sum without a temporary array:

sum(Iterators.flatten((Lc[j], Lr[e,d[e,j]] for e in Mji)))

(assuming Lc[j] is just a float, which when iterated over behaves like a 1-element container [Lc[j]])