4

I would like to broadcast an operation to all values of a dictionary. For an array, I know I can broadcast an element-wise operation using:

julia> b1 = [1, 2, 3]
julia> b1./2
3-element Array{Float64,1}:
 0.5
 1.0
 1.5

What is an efficient way of broadcasting the same operation to all values of a dictionary? Say, for the dictionary

a1 = Dict("A"=>1, "B"=>2)
Bremsstrahlung
  • 686
  • 1
  • 9
  • 23

1 Answers1

7

An iteration protocol is defined for both keys and values of dictionaries, so you can just do, eg:

julia> d = Dict("a"=>1, "b"=>2)
Dict{String,Int64} with 2 entries:
  "b" => 2
  "a" => 1

julia> values(d).^2
2-element Array{Int64,1}:
 4
 1

If you want to alter the dictionary in-place, use map!, eg:

julia> map!(x->x^2, values(d))
Base.ValueIterator for a Dict{String,Int64} with 2 entries. Values:
  4
  1

julia> d
Dict{String,Int64} with 2 entries:
  "b" => 4
  "a" => 1

However, your function must output a type that can be converted back to the dictionary value type. In my example, I'm squaring Int which yields Int. However, in the question you are dividing by 2, which obviously yields Float64. If the float cannot be converted back to an integer, then you'll get an error.

Note, you can broadcast over keys also, e.g.:

julia> f(x) = "hello mr $(x)"
f (generic function with 1 method)

julia> f.(keys(d))
2-element Array{String,1}:
 "hello mr b"
 "hello mr a"

but this can not be done in-place, i.e. you can't use map! on keys.

Importantly, note that you should not instantiate the collection. Indeed, this would be inefficient. So avoid constructs like: collect(values(d)) ./ 2.

Colin T Bowers
  • 18,106
  • 8
  • 61
  • 89
  • This leads to my desired output. However, I would like the new values to overwrite the old ones in the dictionary. How do I do that? – Bremsstrahlung May 21 '20 at 04:52