How to determine when to broadcast

I have some code that needs to perform a setindex!(A::Array, X::Float64, Indices) using A[Indices...] = X or broadcasting A[Indices...] .= X. Right now until that is called I don’t know if Indices will be a Vector of Ints or a Vector of Vector of Ints (when I need to broadcast).

I have a hack, but is there a good way to use Julia Base functions to determine whether broadcasting will be necessary?

You could try Iterators.flatten, which will unravel each element of your vector X. In Julia, numbers are also iterable, i.e. they return their value, so both cases of Vectors or Ints or Vector of Vector of Ints should work.

As for whether broadcasting is necessary, it should not be necessary if X is already computed. However, broadcasting can help avoid allocations if you would like to perform a calculation with X, such as A .= X .* 2

1 Like

Do you have an example of inputs and outputs in mind? Something seems off when you go from saying X::Float64 to saying X::Vector{Int} or X::Vector{Vector{Int}}. scratch that after edit. But examples would still help.

Sorry, that was my mistake, it is Indices which varies. Admittedly it is not perfect code, I’m building on a code base that I didn’t fully write.

So the example would be this:

I could have

A = [1,2,3]
X = 3
Indices = [2]

A[Indices...] = 3

I could also have

A = [1,2,3]
X = 3
Indices = [[2]]

A[Indices...] = 3

which will throw

julia> A[Indices...] = 3
ERROR: ArgumentError: indexed assignment with a single value to possibly many locations is not supported; perhaps use broadcasting `.=` instead?
 [1] setindex_shape_check(::Int64, ::Int64)
   @ Base ./indices.jl:261
 [2] _unsafe_setindex!(::IndexLinear, A::Vector{Int64}, x::Int64, I::Vector{Int64})
   @ Base ./multidimensional.jl:953
 [3] _setindex!
   @ Base ./multidimensional.jl:944 [inlined]
 [4] setindex!(A::Vector{Int64}, v::Int64, I::Vector{Int64})
   @ Base ./abstractarray.jl:1393
 [5] top-level scope
   @ REPL[18]:1

In the second case I need to broadcast, I’m looking for the best way possible to check if I will need to broadcast. I’ve done it but want it to be robust, and thought there may be some Julia base functions that would help instead of reinventing the wheel :slight_smile:

Oh, that is not what broadcasting is for, the error message is referring to something else. You’re trying to process improper Indices to proper indices. A[Indices...] works for [2] because it splats to the proper A[2]. You could accomplish the same thing with A[Indices[begin]]. A[Indices[begin][begin]] would work for Indices = [[2]], but you really don’t want to do that.

I’m guessing that in the actual code, Indices does have a more apparent structure that we can process to proper indices in a more general manner. Is the destination array a matrix, it would be good to have >1 dimension to distinguish linear and Cartesian indices, but not more where printing gets difficult. Saying the expected outcome (#=commented out=#) in addition to the inputs would also help a lot.

This should get the job done

A[collect(Iterators.flatten(Indices))] .= 3

Thank you both! @Benny agreed I should get to the bottom of the structure to do this more properly, I’m going to look into the preceding steps that generate the Indices and see what I can simply. @lxvm that works thank you!

Single- and multi-dimensional Arrays · The Julia Language
Hopefully it helps to have the manual section visible as you mull over the code.

1 Like

In general, this kind of situation is well solved with multiple dispatch ie

setitems!(A, X, indices::Vector{Vector}) = A[indices...] .= X
setitems!(A, X, indices::Vector) = A[indices...] = X


setitems!(A, X, indices) # don't need to check what type indices is here
1 Like

Great idea!