Jacob233
Jacob233

Reputation: 312

Two dimensional dictionary with list as a value python

I'm writing a simple parser for exercise and I have a problem with saving downloaded data to a dictionary.

data = {"":{"":[]}}

with open("Training_01.txt", "r") as open_file:
    text = open_file.read()
    text = text.split("\n")

    for i in text:
        i = i.split("/")
        try:
           data[i[1]] = {i[2]:[].append(i[3])}
        except:
            print("Can't")

This is an example of the data that I want to parse:

/a/abbey/sun_aobrvxdhumowzajn.jpg
/a/abbey/sun_apstfzmbeiwbjqvb.jpg
/a/abbey/sun_apyilcssuybumhbu.jpg
/a/abbey/sun_arrohcvipmrghrzh.jpg
/a/abbey/sun_asgeghboyugsatii.jpg
/a/airplane_cabin/sun_blczihbhbntqccux.jpg
/a/airplane_cabin/sun_ayzaayjpoknjvpds.jpg
/a/airplane_cabin/sun_afuoinkozbbhqksk.jpg
/b/butte/sun_asfnwmuzhtjrztns.jpg
/b/butte/sun_ajzkngginlffsozz.jpg
/b/butte/sun_adonkmfgywrhpakt.jpg
/c/cabin/outdoor/sun_atqvmarllxqynnks.jpg
/c/cabin/outdoor/sun_acfcobswmnoyhyfi.jpg
/c/cabin/outdoor/sun_afgjdqosvakljsmc.jpg

I want to create dictionary with "a","b","c" or any letter, as a key (I cant hard code it) with dictionary as a value that contains place where images were taken and list of images.

But when I want to read my saved data I'm getting None as a value

 print(data["a"])
 Output: {'auto_factory': None}

Upvotes: 3

Views: 1440

Answers (2)

Echan
Echan

Reputation: 1415

Because data[i[1]] = {i[2]:[].append(i[3])} create a new 2nd layer dictionary everytime.

This is a possible solution. It is the cleanest solution, but it shows step by step. It creates a new dict and list if the key is not in the last layer dict. But it append value to the list if the dict has the key.

data = {"":{"":[]}}

with open("Training_01.txt", "r") as open_file:
    text = open_file.read()
    text = text.split("\n")

    for i in text:

        i = i.split("/")
        key_1 = i[1]
        key_2 = i[2]
        value = i[3]
        try:
            if key_1 in data.keys():  # Whether the key i[1] is in the 1st layer of the Dict
                if key_2 in data[key_1].keys():  # Whether the key i[2] is in the 2nd layer of the Dict
                    # Yes, Append to the list
                    data[key_1][key_2].append(value)
                else:
                    # No, Creat a new list
                    data[key_1][key_2] = [value]
            # if i[1] not in the 1st layer, creat a 2nd layer dict with i[2] as key, i[3] as value
            else:
                data[key_1] =  {key_2:[value]}
        except:


             print("Can't")
    print(data['a'])

Upvotes: 1

Ivan Velichko
Ivan Velichko

Reputation: 6709

Try to use defaultdict from python stdlib. It's very convenient in situations like this:

from collections import defaultdict

data = defaultdict(lambda: defaultdict(list))

with open("Training_01.txt", "r") as open_file:
    text = open_file.read()
    text = text.split("\n")

    for line in text:
        try:
            _, key, subkey, rem = line.split("/", 3)
            data[key][subkey].append(rem)        
        except:
            print("Can't")

print(data)

Explanation: the first time you access data (which is a dictionary) with a not existing key, a new entry for such a key will be created. This entry is going to be again a defaultdict, but the first try you access it with a not existing key, again a new (nested this time) entry will be created. And this entry will be a list. So, then you can safely append a new element to such a list.

UPD: Here is a way to implement the same requirement but without defaultdict:

data = {}  # just a plain dict
# for ...:
    data[key] = data.get(key, {})  # try to access the key, if it doesn't exist - create a new dict entry for such a key
    data[key][subkey] = data[key].get(subkey, [])  # same as above but for the sub key
    data[key][subkey].append(rem)  # finally do the job

Upvotes: 4

Related Questions