0

For the purpose of this question I simplified the code but basically I am parsing an oracle table and create a data map of it which I will then use later in the code. I try to save it to a dict of dicts of lists. Instead of getting a dict (e.g. dict['a']['b']) holding a list of tuples I end up having a key referencing a list with only one tuple. Last that got appended.


from collections import defaultdict

somelist = ['a:b:1:2','a:b:3:4','a:b:5:6']
somehash = defaultdict(dict)

for val in somelist:
    (a,b,c,d) = val.split(":")
    somehash[a] = defaultdict(list)
    somehash[a][b].append((c,d))

for i in somehash['a']['b']:
    print i

I expect the output to read

('1', '2')

('3', '4')

('5', '6')

Yet I see only

('5', '6')

  • Because you're resetting `somehash[a]` to an empty defaultdict on every iteration? – glibdud Apr 18 '19 at 14:57
  • 1
    Is [this](https://stackoverflow.com/questions/33080869/python-how-to-create-a-dict-of-dict-of-list-with-defaultdict) what you're trying to do? – glibdud Apr 18 '19 at 15:00
  • would `defaultdict` not skip resetting the key if it already exists? – Anna Barska Apr 18 '19 at 15:03
  • The append line works that way, but `somehash[a] = defaultdict(list)` will rebind `somehash[a]` each time. You need a nested defaultdict, which is addressed in the link I posted above. – glibdud Apr 18 '19 at 15:08
  • @glibdud - yeah - that is exactly what I was looking for. Thanks – Anna Barska Apr 18 '19 at 15:43

2 Answers2

0
from collections import defaultdict

somelist = ['a:b:1:2','a:b:3:4','a:b:5:6']
somehash = defaultdict(dict)

for val in somelist:
    (a,b,c,d) = val.split(":")
    if a not in somehash: # only initiate the dict for a if it has not existed yet
        somehash[a] = defaultdict(dict)
        somehash[a][b] = list()
    somehash[a][b].append((c,d))

for i in somehash['a']['b']:
    print i

SalaryNotFound
  • 224
  • 1
  • 8
  • That worked. Thanks. Needed to slightly redo it though as 'b' in 'a:b' may change to c (e.g. a:c:3:4) so added this `if b not in somehash[a]:` to also make sure [a][b] list is defined and protect if from being overwritten at the same time. Thanks – Anna Barska Apr 18 '19 at 15:28
0

here is the code that works (based on @galibdud's link):

from collections import defaultdict

somelist = ['a:b:1:2','a:b:3:4','a:b:5:6','a:c:9:6','a:c:5:11']

somehash = defaultdict(lambda: defaultdict(list))

for val in somelist:
    (a,b,c,d) = val.split(":")
    somehash[a][b].append((c,d))


for i,k in somehash.iteritems():
    print i, ' goes with ', k
    for a,b in k.iteritems():
        print a, ' goes with ', b
        for t in b:
            print t

Output now reads

a goes with defaultdict(<type 'list'>, {'c': [('9', '6'), ('5', '11')], 'b': [('1', '2'), ('3', '4'), ('5', '6')]})
c goes with [('9', '6'), ('5', '11')]
('9', '6')
('5', '11')
b goes with [('1', '2'), ('3', '4'), ('5', '6')]
('1', '2')
('3', '4')
('5', '6')