Reputation: 1091
I have a string of keys separated by a delimiter |
followed by a value.
The string might be
key1|key2|key3=value
This should parse as
dct[key1][key2][key3] = value
The individual dictionaries might already exist.
To get the prototype started I have hard coded the creation of the dictionaries like this (fields is the main dictionary - already existing, s is the sequence of keys separated by |
(pipe) :
keys=s.split('|')
if len(keys) == 1:
fields[keys[0]] = field_data
elif len(keys) == 2:
if keys[0] not in fields:
fields[keys[0]] = {}
fields[keys[0]][keys[1]] = field_data
I extended this for three-depth dictionary, but it is very inelegant I know.
Upvotes: 0
Views: 210
Reputation:
This will assume that your keys and values are strings. I.E:
key1|key2|key3=value
dct['key1']['key2']['key3'] = 'value'
# The literal strings
Then you can create a function that takes a string and splits it.
def str_as_key(string, dictionary=None):
dictionary = dictionary or {}
keys = string.split("|")
keys[-1:] = keys[-1].split("=")
value = keys.pop()
dicti = [dictionary, []]
for key in keys:
dicti = [dicti[0].get(key), dicti[1] + [key]]
if not isinstance(dicti[0], dict):
exec("dictionary['{0}'] = {1}; dicti[0] = {1}".format("']['".join(dicti[1]), '{}'))
exec("dictionary['{}'] = '{}'".format("']['".join(keys), value))
return dictionary
The thing about this method is that it doesn't have to create a new dictionary. It can update one and leave other keys untouched. e.g:
>>> s = "key1|key2|key3=value"
>>> str_as_key(s, {})
{'key1': {'key2': {'key3': 'value'}}}
>>> str_as_key(s, {"key1": {"key2": 12, "foo": "bar"}, "pi": 3.14})
{'pi': 3.14, 'key1': {'foo': 'bar', 'key2': {'key3': 'value'}}}
Upvotes: 1
Reputation: 214969
For example,
s = "key1|key2|key3=value"
keys, value = s.split('=')
keys = keys.split('|')
base = {}
reduce(
lambda d, k: d.setdefault(k, {}),
keys[:-1],
base
)[keys[-1]] = value
print base # {'key1': {'key2': {'key3': 'value'}}}
If you need this often, it might be worth making a class:
class NestedDict(dict):
def __setitem__(self, key, value):
if not isinstance(key, collections.Iterable) or isinstance(key, basestring):
super(NestedDict, self).__setitem__(key, value)
return
keys = list(key)
reduce(
lambda d, k: d.setdefault(k, {}),
keys[:-1],
self
)[keys[-1]] = value
and then:
s = "key1|key2|key3=value"
keys, value = s.split('=')
base = NestedDict()
base[keys.split('|')] = value
print base # {'key1': {'key2': {'key3': 'value'}}}
Upvotes: 2
Reputation:
Why do you need a dictionary with three dimensions? Use a simple dictionary with tuples as keys:
s = "key1|key2|key3=value"
ks, v = s.split("=")
dct = {}
dct[ks] = v
Now you can access dct
like this:
print(dct[("key1", "key2", "key3")])
Output:
value
Upvotes: 2