Search code examples
dictionaryjuliaelementwise-operations

Dictionary element-wise operations in Julia


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)

Solution

  • 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.