How to parse a text file into a nested dictionary and save it

Hello,
I have a text file that goes like this:
bulbasaur,5,25.0,grass
charmander,3,100.0,fire
gyrados,1,1000.0,water,flying
squirtle,2,50.0,water

I’ve been trying to write a code that would load the texts as a nested dictionary like this:
’ ’ ’ python
pokemon = {
‘charmander’:{‘quantity’:3,‘fee’:100,‘powers’:[‘fire’]},
‘squirtle’:{‘quantity’:2,‘fee’:50,‘powers’:[‘water’]},
‘bulbasaur’:{‘quantity’:5,‘fee’:25,‘powers’:[‘grass’]},
‘gyrados’:{‘quantity’:1,‘fee’:1000,‘powers’:[‘water’,‘flying’]}
}
’ ’ ’
For now I have the following code:

’ ’ ‘python
pokemon = {}
database_filename = ‘pokemons.txt’
with open(database_filename) as file:
for line in file:
attributes = line.strip().split(’,’)
#print(attributes)
pokemon[attributes[0]] = [int(attributes[1]), float(attributes[2]), attributes[3:]]
def save():
with open(database_filename, ‘w’) as f:
for pok in sorted(pokemon):
f.write(pok + ‘,’ + str(pokemon[pok][0]) + ‘,’ + str(pokemon[pok][1]) + ‘,’ + ‘,’.join(pokemon[pok][2]) + ‘\n’)
’ ’ ’
I’ve written it so that (1) it reads the text file into a list and (2)saves it as a list but I am stuck on basically doing it the same for a nested dictionary

Hi Zulaa,

First off, thank you for pasting your code and trying to format it! You almost had it right, you just need use 3 backticks (`) instead of apostrophes ('). If you could edit you post so it displays properly, that would be great, otherwise we can’t be sure of what your code really looks like and also can’t easily copy-paste it ourselves.

Second, you should probably look into using the csv module. It’s designed to read and write data like this and handles most of the parsing for you.

https://docs.python.org/3/library/csv.html

Although if you go this route, you will have to do some extra work as your nested dictionaries and lists will be stored as strings.

What are you doing with this data? Since you called it database_file in your code, I’m guessing you’re saving some sort of state in your program. Would you consider a different file format? Python has the json module which would allow you to save simple dictionaries like yours to a file very easily.

https://docs.python.org/3/library/json.html

Example:
Your pokemons.txt file would look like this:

{
    "bulbasaur": {
        "fee": 25,
        "powers": [
            "grass"
        ],
        "quantity": 5
    },
    "charmander": {
        "fee": 100,
        "powers": [
            "fire"
        ],
        "quantity": 3
    },
    "gyrados": {
        "fee": 1000,
        "powers": [
            "water",
            "flying"
        ],
        "quantity": 1
    },
    "squirtle": {
        "fee": 50,
        "powers": [
            "water"
        ],
        "quantity": 2
    }
}

and you would use this code to read it and save it:

import json

database_filename = 'pokemons.txt'
with open(database_filename) as file:
    pokemon = json.load(file)


def save():
    with open(database_filename, 'w') as f:
        json.dump(pokemon, f, sort_keys=True, indent=4)

In addition to the comments above, you might want to consider the popular Pandas library, which makes working with tabular data much easier. You can read your CSV file into a Pandas DataFrame in one line, df = pandas.read_csv(database_filename, names=['quantity', 'fee', 'powers'], index_col=0), and it will automatically convert all the data types for you. You can then output it to a Python dict in the specified format with df.to_dict(orient='index'), to a JSON file with df.to_json(json_filename, orient='index') or to your original CSV with df.to_csv(database_filename). You can sort your df with df.sort_index()

However, there is one potential problem with either this approach or the previous suggested csv based one—you have a variable number of powers fields, which it looks like you intend to read as a nested list. Bringing in a bit of domain-specific knowledge, it looks like this corresponds to a Pokemon’s “Type”, which per Bulbapedia, a Pokemon can only have one or two types. Thus, the simplest way to handle this is to just declare two columns, type1 and type2, and Pandas (or csv) will fill in the second one with a full value if it is not present. Of course, that doesn’t get you a list in your output data structure, but is a lot simpler to work with; once you get your dict, you can concatenate them into a list, e.g. something like data_dict['types'] = [data_dict.pop(f'type{n}') for n in [1, 2] if f'type{n}' in data_dict].