How to initialize and manipulate Dicts of Dicts?

I am trying to initialize and manipulate Dicts of Dicts, starting with this one:

using Dates
clcdates=Date(2022,7):Month(1):Date(2023,12)
dacc=Dict("MatA"=>Dict(Date(2022,7)=>751.19,Date(2023,1)=>7.98),
            "MatB"=>Dict(Date(2022,10)=>94.25));

So far, so good. Now I want to initialize another Dict of the same type and with the same keys, called acc that is supposed to record the temporal evolution of MatA and MatB in the timespan given by clcdates. Obviously, acc is much more densely populated than dacc, which holds only the changes that occur at irregular dates. I tried:

acc=begin
    for dak in keys(dacc)
        Dict(dak=>Dict(clcdates[1]=>0))
        for m in clcdates[2:end]
            Dict(dak=>Dict(clcdates[1]=>NaN))
        end
    end
end => Dict{String,Dict{Date,Float64}}()
mo=clcdates[1]
for (im,m) in enumerate(clcdates)
    for dak in keys(dacc)
        if haskey(dacc[dak],m)
            acc[dak][m]=acc[dak][mo]+dacc[dak][m] #
        elseif im > 1
            if acc[dak][mo] == 0
                acc[dak][m]=0
                acc[dak][mo]=NaN
            else
                acc[dak][m]=acc[dak][mo]
            end
        end
    end
    mo=m
end

This doesn’t work. @show tells me that after the begin...end block, I have acc = nothing => Dict{String, Dict{Date, Float64}}(), and then the first pass of the loop fails with:

MethodError: no method matching getindex(::Pair{Nothing, Dict{String, Dict{Date, Float64}}}, ::String)

Closest candidates are:
  getindex(::Pair, ::Int64)
   @ Base pair.jl:51
  getindex(::Pair, ::Real)
   @ Base pair.jl:52


Stacktrace:
 [1] top-level scope
   @ ./In[34]:18

Line 18 is the line I have marked with # at the end. What’s wrong here? Why is acc nothing, and what does the error message mean? Is the entire approach misguided?

It’s only a bit clear what you want to try here. But doing it just with a loop looks like:

acc=Dict{String,Dict{Date,Float64}}()
for dak in keys(dacc)
   acc[dak]=Dict{Date,Float64}()
   for m in clcdates[1:end]
       acc[dak][m]=NaN
   end
end

Is this what you want to be acc in your first step? (I didn’t look into the next loop for now…)

Not quite - I do indeed want the entries for the first date to be 0, not NaN (for reasons relating to the next loop). I had already tried something like that but was told that the key of the Dict (“MatB” in this case) was not found. I don’t understand that, because the initialization should have generated it, I think.

Ok, this is just a special case. Just implement it in my proposal as you wish. But beware: 0 is an Int not a Float64.

Well, as I said: I did, but the error I get is that the key is not known.

acc=Dict{String,Dict{Date,Float64}}()
for dak in keys(dacc)
   acc[dak]=Dict{Date,Float64}()
   acc[dak][clcdates[1]]=0
   for m in clcdates[2:end]
       acc[dak][m]=NaN
   end
end

mo=clcdates[1]
for (im,m) in enumerate(clcdates)
    for dak in keys(dacc)
        if haskey(dacc[dak],m)
            acc[dak][m]=acc[dak][mo]+dacc[dak][m] #
        elseif im > 1
            if acc[dak][mo] == 0
                acc[dak][m]=0
                acc[dak][mo]=NaN
            else
                acc[dak][m]=acc[dak][mo]
            end
        end
    end
    mo=m
end

Using the code proposed by Oheil and the one written by you, this comes out.
Is that what you wanted?

julia> acc["MatB"]
Dict{Date, Float64} with 18 entries:
  Date("2023-10-01") => 94.25
  Date("2022-10-01") => 94.25
  Date("2023-07-01") => 94.25
  Date("2022-11-01") => 94.25
  Date("2023-12-01") => 94.25
  Date("2023-02-01") => 94.25
  Date("2022-07-01") => NaN
  Date("2023-04-01") => 94.25
  Date("2023-11-01") => 94.25
  Date("2023-05-01") => 94.25
  Date("2023-01-01") => 94.25
  Date("2023-03-01") => 94.25
  Date("2023-08-01") => 94.25
  Date("2023-09-01") => 94.25
  Date("2022-08-01") => NaN
  Date("2022-12-01") => 94.25
  Date("2022-09-01") => 0.0
  Date("2023-06-01") => 94.25

julia> acc["MatA"]
Dict{Date, Float64} with 18 entries:
  Date("2023-10-01") => 759.17
  Date("2022-10-01") => 751.19
  Date("2023-07-01") => 759.17
  Date("2022-11-01") => 751.19
  Date("2023-12-01") => 759.17
  Date("2023-02-01") => 759.17
  Date("2022-07-01") => 751.19
  Date("2023-04-01") => 759.17
  Date("2023-11-01") => 759.17
  Date("2023-05-01") => 759.17
  Date("2023-01-01") => 759.17
  Date("2023-03-01") => 759.17
  Date("2023-08-01") => 759.17
  Date("2023-09-01") => 759.17
  Date("2022-08-01") => 751.19
  Date("2022-12-01") => 751.19
  Date("2022-09-01") => 751.19
  Date("2023-06-01") => 759.17
1 Like

Yes, that’s it more or less! Now I see that I stupidly missed an assignment to acc in the first loop and overwrote another one several times in that earlier attempt I didn’t show.
Thank you very much!