2
a = {
    'user': {
        'username': 'mic_jack',    
        'name': {
            'first': 'Micheal',
            'last': 'Jackson'
        },
        'email': '[email protected]',

        #...
        #... Infinite level of another nested dict
    }     
}

str_key_1 = 'user.username=john'
str_key_2 = 'user.name.last=henry'
#...
#str_key_n = 'user.level2.level3...leveln=XXX'

Let's consider this 'str_key' string, goes with infinite number of dots/levels.

Expected Output:

a = {
    'user': {
        'username': 'john',     # username, should be replace    
        'name': {
            'first': 'Micheal',
            'last': 'henry'     # lastname, should be replace 
        },
        'email': '[email protected]',

        ...
        ... # Infinite level of another nested dict
    }     
}

I'm expecting the answers for applying 'n' Level of nested key string, rather than simply replacing by a['user']['username'] = 'John' statically. Answers must be work for any number of 'dotted' string values.

Thanks in advance!

5
  • 2
    Really feels like an XY problem, what are you trying to accomplish? Commented Jan 18, 2019 at 13:15
  • Are you saying you want a string for every possible combination of depth through n nested dicts? Commented Jan 18, 2019 at 13:15
  • @ruohola I have a 'config' dictionary object in 'config.py'. The user have the option to override this value from 'command line' like (e.g python run.py env=dev user.name.last=John) Commented Jan 18, 2019 at 13:18
  • 1
    @JaiK have you considered that your config dictionary could be in a simpler format? Commented Jan 18, 2019 at 13:20
  • @ruohola Some time, I want to group them as a single unit, For example, the config for 'Database' are grouped into db: {'HOST'='X', 'PORT': 8080, 'USERNAME': 'XXX', 'PASSWORD': 'YYY'}, destination output is grouped into dest: {'DIR_PATH': '/output', 'FILE_EXT': 'csv'} etc Commented Jan 18, 2019 at 13:23

4 Answers 4

2

There are three steps:

  1. Separate the key-value pair string into a fully-qualified key and value.
  2. Split the key into path components.
  3. Traverse the dictionary to find the relevant value to update.

Here's an example of what the code might look like:

# Split by the delimiter, making sure to split once only
# to prevent splitting when the delimiter appears in the value
key, value = str_key_n.split("=", 1)

# Break the dot-joined key into parts that form a path
key_parts = key.split(".")

# The last part is required to update the dictionary
last_part = key_parts.pop()

# Traverse the dictionary using the parts
current = a
while key_parts:
  current = current[key_parts.pop(0)]

# Update the value
current[last_part] = value
Sign up to request clarification or add additional context in comments.

2 Comments

Is there any particular reason for using this temp. var current = a, because of without this assignment also the above code is working. I meant, directly using 'a' instead of 'current'.
@jai without assignment a will become "{'first': 'Micheal', 'last': 'henry'}"
0

I'd go with a recursive function to accomplish this, assuming your key value strings are all valid:

def assign_value(sample_dict, str_keys, value):
  access_key = str_keys[0]

  if len(str_keys) == 1:
    sample_dict[access_key] = value
  else:
    sample_dict[access_key] = assign_value(sample_dict[access_key], str_keys[1:], value)

  return sample_dict

The idea is to traverse your dict until you hit the lowest key and then we assign our new value to that last key;

if __name__ == "__main__":
  sample_dict = {
      'user': {
          'username': 'mic_jack',    
          'name': {
              'first': 'Micheal',
              'last': 'Jackson'
          },
          'email': '[email protected]'
      }     
  }

  str_key_1 = 'user.username=john'
  str_keys_1, value_1 = str_key_1.split('=')
  sample_dict = assign_value(sample_dict, str_keys_1.split('.'), value_1)

  print("result: {} ".format(sample_dict))


  str_key_2 = 'user.name.last=henry'
  str_keys_2, value_2 = str_key_2.split('=')
  sample_dict = assign_value(sample_dict, str_keys_2.split('.'), value_2)

  print("result: {}".format(sample_dict))

To use the assign_value you would need to split your original key to the keys and value as seen above;

Comments

0

If you're okay with using exec() and modify your str_key(s), you could do something like:

def get_keys_value(string):
    keys, value = string.split("=")
    return keys, value

def get_exec_string(dict_name, keys):
    exec_string = dict_name
    for key in keys.split("."):
        exec_string = exec_string + "[" + key + "]"
    exec_string = exec_string + "=" + "value"
    return exec_string

str_key_1 = "'user'.'username'=john"
str_key_2 = "'user'.'name'.'last'=henry"
str_key_list = [str_key_1, str_key_2]

for str_key in str_key_list:
    keys, value = get_keys_value(str_key) # split into key-string and value
    exec_string = get_exec_string("a", keys) # extract keys from key-string 
    exec(exec_string)

print(a)
# prints {'user': {'email': '[email protected]', 'name': {'last': 'henry', 'first': 'Micheal'}, 'username': 'john'}}

Comments

0
str_key_1 = 'user.username=john'
str_key_2 = 'user.name.last=henry'

a = {
    'user': {
        'username': 'mic_jack',    
        'name': {
            'first': 'Micheal',
            'last': 'Jackson'
        },
        'email': '[email protected]',

        #...
        #... Infinite level of another nested dict
    }     
}

def MutateDict(key):
    strkey, strval = key.split('=')[0], key.split('=')[1]
    strkeys = strkey.split('.')
    print("strkeys = " ,strkeys)
    target = a
    k = ""
    for k in strkeys:
        print(target.keys())
        if k in target.keys():
            prevTarget = target
            target = target[k]
        else:
            print ("Invalid key specified")
            return
    prevTarget[k] = strval


MutateDict(str_key_1)

print(a)

MutateDict(str_key_2)

print(a)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.