Reputation: 65
For a "heath-check" project, I'm trying to create a multi-dimension array from strings that are written in a text file.
Currently I have it working with single variables like this:
someParameter1 = someValue1 # With some comments
someParameter2 = someValue2 # With some other comments
This will be translated into a dictionary:
ini['someParameter1'] = 'someValue1'
ini['someParameter2'] = 'someValue2'
Now I just added checks on tables and therefor I use two-dimensional array's, build from dash-separated strings like this:
someTable-someParameter1 = someValue1 # With some comments
someTable-someParameter2 = someValue2 # With some other comments
This will be translated into a two-level dictionary:
ini['someTable']['someParameter1'] = 'someValue1'
ini['someTable']['someParameter2'] = 'someValue2'
For this I hard-coded a limit on 2 fields before the '=' sign:
# In case the key contains a dash, create a 2-dimensional key
for inikey in list(ini): # loop thru the ini to find key's with a dash
if '-' in inikey:
part1,part2 = inikey.split('-',1) # <= Only split on the first dash
try:
ini[part1][part2] = ini[inikey]
except KeyError: # In case ini[part1] does not exist yet
ini[part1] = {}
ini[part1][part2] = ini[inikey]
Because of this, when I have in my config file: aaa-bbb-ccc-ddd = xyz
, this will be translated to ini['aaa']['bbb-ccc-ddd'] = 'xyz'
Now I look for a nice trick to create ini['aaa']['bbb]['ccc']['ddd'] = 'xyz'
without writing a piece of code for every expected amount of levels.
So if possible also with 3, 4, or whatever number of words before the =, creating a list with unknown amount of dimensions, as deep as needed.
Upvotes: 2
Views: 171
Reputation: 106891
You can split the key by dashes into parent keys and a final key, then iterate through the parent keys to build the sub-dicts if a parent key is missing, and finally assign the current value to the final key of the current node for each line of input:
from io import StringIO
file = StringIO('''someParameter1 = someValue1
someParameter2 = someValue2
someTable-someParameter1 = someValue1
someTable-someParameter2 = someValue2
aaa-bbb-ccc-ddd = xyz''')
ini = {}
for line in file:
node = ini
key, value = line.rstrip().split(' = ')
*parents, key = key.split('-')
for parent in parents:
node[parent] = node = node.get(parent, {})
node[key] = value
ini
would become:
{'someParameter1': 'someValue1',
'someParameter2': 'someValue2',
'someTable': {'someParameter1': 'someValue1', 'someParameter2': 'someValue2'},
'aaa': {'bbb': {'ccc': {'ddd': 'xyz'}}}}
Demo: https://repl.it/@blhsing/ForkedSufficientNumericalanalysis
Upvotes: 1
Reputation: 24153
You can use defaultdict
and create it with a default dict. If you call that a Tree
, we have a recursive data structure:
from collections import defaultdict
def Tree():
return defaultdict(Tree)
This will create new sub trees every time a new key is used:
>>> tree = Tree()
>>> tree['a']['b']['c'] = 123
If we have a list of keys, we can loop through them keeping track of each sub-tree until we've use all but the last key. Then we set the value for the last key in the last sub-tree:
ini = Tree()
config_line = 'aaa-bbb-ccc-ddd = xyz'
keys, value = config_line.split(' = ')
keys = keys.split('-')
subtree = ini
for key in keys[:-1]:
subtree = subtree[key]
subtree[keys[-1]] = value
Upvotes: 2