0

I'm attempting to create a data structure that keeps track of occurrences per month over a number of years. I have determined a dictionary of lists to be the best option. I want to create something like this structure (year: list of twelve integers representing occurrences per month):

yeardict = {
'2007':[0,1,2,0,3,4,1,3,4,0,6,3]
'2008':[0,1,2,0,3,4,1,3,5,0,6,3]
'2010':[7,1,3,0,2,6,0,6,1,8,1,4]
}

I am taking as an input, a dictionary that looks like this:

monthdict = {
'2007-03':4,
'2007-05':2,
'2008-02':8
etc.
}

I have my code loop through the second dictionary, first paying attention to the first 4 characters in the key (the year) and if that is NOT in the dictionary, then I initialize that key along with the value of twelve blank months in a list form: [0,0,0,0,0,0,0,0,0,0,0,0], then change the value of the item in that list of the position of the month to whatever the value is. If the year is in the dictionary, then I just want to set the item in the list to equal the value that month. My question is how do I access and set a specific item in a list within a dictionary. I am running into a number of errors which are not particularly helpful to google.

here is my code:

    yeardict = {}
    for key in sorted(monthdict):
        dyear = str(key)[0:4]
        dmonth = str(key)[5:]
        output += "year: "+dyear+" month: "+dmonth
        if dyear in yeardict:
            pass
#            yeardict[str(key)[0:4]][str(key)[5:]]=monthdict(key)                
        else:
            yeardict[str(key)[0:4]]=[0,0,0,0,0,0,0,0,0,0,0,0]
#            yeardict[int(dyear)][int(dmonth)]=monthdict(key)

The two lines that are commented out are where I want to actually set the values, and they introduce one of two errors when I add them to my code: 1. 'dict' is not callable 2. KeyError: 2009

Let me know if I can clarify anything. Thank you for looking.

3 Answers3

5

Here is how I would write this:

yeardict = {}
for key in monthdict:
    try:
        dyear, dmonth = map(int, key.split('-'))
    except Exception:
        continue  # you may want to log something about the format not matching
    if dyear not in yeardict:
        yeardict[dyear] = [0]*12
    yeardict[dyear][dmonth-1] = monthdict[key]

Note that I assumed that January in your date format is 01 not 00, if that is not the case just use dmonth instead of dmonth-1 in the last line.

Andrew Clark
  • 202,379
  • 35
  • 273
  • 306
  • 1
    +1, but could be shortened further to avoid the `if` statement by using `yeardict.setdefault(year, [0]*12)[dmonth-1] = monthdict[key]` – Nisan.H Feb 27 '13 at 21:58
  • This is perfect. Thank you for fixing my problem and making it look much neater! – Miles Lincoln Feb 27 '13 at 22:07
  • I ran this on some of my larger actual (monthdict) dictionaries, and they return: "IndexError: list assignment index out of range" Any ideas where to start debugging? Some answers say to append, rather than set equal ( http://stackoverflow.com/questions/5653533/indexerror-list-assignment-index-out-of-range ), but that wouldn't work in my case where ordering matters. – Miles Lincoln Feb 27 '13 at 23:40
  • @MilesLincoln Any chance you have 13 or higher as a month value? – Andrew Clark Feb 28 '13 at 00:12
  • @Nisan.H That would be shorter, but it may also unnecessarily create a lot of unused lists. – Andrew Clark Feb 28 '13 at 00:13
  • @F.J Right. I didn't consider that earlier. – Nisan.H Feb 28 '13 at 01:01
  • @F.J that's possible. I'll look carefully through my code to see if that's the case. in the meantime, can I add something like this to bypass the error: "if dmonth not in range(1,13): break" after the exception? – Miles Lincoln Feb 28 '13 at 02:05
  • @MilesLincoln Yeah a check like that would probably be a good idea. I would probably put something like `assert dmonth in range(1, 13)` at the end of the `try` block. – Andrew Clark Feb 28 '13 at 16:47
0
defaultlist = 12*[0]
years = {}
monthdict = {
'2007-03':4,
'2007-05':2,
'2008-02':8
}

for date, val in monthdict.items():
    (year, month) = date.split("-")
    occurences = list(years.get(year, defaultlist))
    occurences[int(month)-1] = val
    years[year] = occurences

edit actually, defaultdict won't help. Re wrote answer to just do a default get and make a copy of that list

user2079098
  • 132
  • 9
0

Does this have the behavior you want?

>>> yeardict = {}
>>> monthdict = {
... '2007-03':4,
... '2007-05':2,
... '2008-02':8 }
>>> for key in sorted(monthdict):
...     dyear = str(key)[0:4]
...     dmonth = str(key)[5:]
...     if dyear in yeardict:
...         yeardict[dyear][int(dmonth)-1]=monthdict[key]
...     else:
...         yeardict[dyear]=[0]*12
...         yeardict[dyear][int(dmonth)-1]=monthdict[key]
... 
>>> yeardict
{'2008': [0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], '2007': [0, 0, 4, 0, 2, 0, 0, 0, 0, 0, 0, 0]}
>>> 
Logan
  • 1,614
  • 1
  • 14
  • 27