'Convert camelCase to snakeCase

I have a dictionary something like this:

{
     'firstName': 'abc',
     'lastName': 'xyz',
     'favoriteMovies': ['Star Wars', 'The lone ranger'],
     'favoriteCountries': [
          {'country': 'China', 'capitalCity': 'Beiging'},
          {'country': 'India', 'capitalCity': 'New Delhi'}
     ]
}

I want to convert it to snake_case like the following

{
    'first_name': 'abc',
    'last_name': 'xyz',
    'favorite_movies': ['Star Wars', 'The lone ranger'],
    'favorite_countries': [
        {'country': 'China', 'capital_city': 'Beiging'},
        {'country': 'India', 'capital_city': 'New Delhi'}
     ]
}  

The dictionary may be of any length depth.

My current solution is

import re

def convert_snake_case_to_camel_case(data):
    required_dict = {}

    for key, value in data.items():
        if type(value) == str:
            new_key = re.sub("([a-z0-9])([A-Z])", r"\1_\2", key).lower()
            required_dict[new_key] = value
        elif type(value) == list and all(list(map(lambda _: isinstance(_, str), value))):
            new_key = re.sub("([a-z0-9])([A-Z])", r"\1_\2", key).lower()
            required_dict[new_key] = value
        elif type(value) == list and all(list(map(lambda _: isinstance(_, dict), value))):
            new_key = re.sub("([a-z0-9])([A-Z])", r"\1_\2", key).lower()
            required_dict[new_key] = list(filter(convert_snake_case_to_camel_case, value))
    return required_dict

But I m not getting the expected result for the nested data.



Solution 1:[1]

data = {
     'firstName': 'abc',
     'lastName': 'xyz',
     'favoriteMovies': ['Star Wars', 'The lone ranger'],
     'favoriteCountries': [
          {'country': 'China', 'capitalCity': 'Beiging'},
          {'country': 'India', 'capitalCity': 'New Delhi'}
     ]
}

new_data = {}
for key, value in data.items():
    new_key_list = ['_' + x.lower() if x.isupper() else x for x in key]
    new_key = ''.join(new_key_list)
    if isinstance(value[0],dict):
        new_value = []
        for item in value:
            temp_dict = {}
            for key2, value2 in item.items():
                new_key_list = ['_' + x.lower() if x.isupper() else x for x in key2]
                new_key = ''.join(new_key_list)
                temp_dict[new_key] = value2
            new_value.append(temp_dict)
        new_data[new_key] = new_value
    else:
        new_data[new_key] = value

Output:

{'first_name': 'abc', 'last_name': 'xyz', 'favorite_movies': ['Star Wars', 'The lone ranger'], 'capital_city': [{'country': 'China', 'capital_city': 'Beiging'}, {'country': 'India', 'capital_city': 'New Delhi'}]}

Solution 2:[2]

Short recursive version:

import re
def to_snake(s):
  return re.sub('([A-Z]\w+$)', '_\\1', s).lower()

def t_dict(d):
   if isinstance(d, list):
      return [t_dict(i) if isinstance(i, (dict, list)) else i for i in d]
   return {to_snake(a):t_dict(b) if isinstance(b, (dict, list)) else b for a, b in d.items()}

data = {'firstName': 'abc', 'lastName': 'xyz', 'favoriteMovies': ['Star Wars', 'The lone ranger'], 'favoriteCountries': [{'country': 'China', 'capitalCity': 'Beiging'}, {'country': 'India', 'capitalCity': 'New Delhi'}]} 
print(t_dict(data))

Output:

{'first_name': 'abc', 'last_name': 'xyz', 
 'favorite_movies': ['Star Wars', 'The lone ranger'], 
 'favorite_countries': [
    {'country': 'China', 'capital_city': 'Beiging'}, 
    {'country': 'India', 'capital_city': 'New Delhi'}
  ]
}

Solution 3:[3]

You could use regex for this.

def camel_to_snake(str):
   return re.sub(r'(?<!^)(?=[A-Z])', '_', str).lower()

Then build another recursive function which converts all the dictionary keys by using the above function.

Solution 4:[4]

Use the humps library

Example

import humps
humps.camelize('jack_in_the_box')  # jackInTheBox
humps.decamelize('rubyTuesdays')  # ruby_tuesdays
humps.pascalize('red_robin')  # RedRobin

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Ajax1234
Solution 3 Mihai Alexandru-Ionut
Solution 4 Phillip Kigenyi