Recursively convert all keys from camelCase to snake_case

2 min read 05-10-2024
Recursively convert all keys from camelCase to snake_case


Taming the Camel: Recursively Transforming CamelCase Keys to Snake_Case

Working with data structures often involves encountering keys formatted in different styles. While camelCase is popular in programming, snake_case is favored in other contexts, such as databases. Transforming keys from one format to another can be a tedious task, especially when dealing with nested dictionaries.

This article explores a concise and efficient solution to this common problem: recursively converting all keys in a dictionary from camelCase to snake_case. Let's dive in.

The Scenario:

Imagine you have a dictionary containing nested data structures, like this:

data = {
    "firstName": "John",
    "lastName": "Doe",
    "address": {
        "street": "123 Main St",
        "city": "Anytown",
        "zipCode": "12345"
    },
    "phoneNumber": "555-123-4567"
}

You need to convert all the keys to snake_case:

expected_data = {
    "first_name": "John",
    "last_name": "Doe",
    "address": {
        "street": "123 Main St",
        "city": "Anytown",
        "zip_code": "12345"
    },
    "phone_number": "555-123-4567"
}

The Recursive Solution:

def to_snake_case(data):
    """Recursively converts camelCase keys to snake_case.

    Args:
        data: The dictionary to transform.

    Returns:
        A new dictionary with all keys converted to snake_case.
    """
    if isinstance(data, dict):
        return {
            to_snake_case(key).replace(" ", "_"): to_snake_case(value)
            for key, value in data.items()
        }
    elif isinstance(data, list):
        return [to_snake_case(item) for item in data]
    else:
        return data

# Example usage
transformed_data = to_snake_case(data)
print(transformed_data) 

Explanation:

The to_snake_case() function utilizes recursion to handle nested dictionaries efficiently.

  1. Base Case: If the input is not a dictionary or a list, it returns the input directly.
  2. Dictionary Handling: If the input is a dictionary, the function iterates through each key-value pair.
    • to_snake_case(key).replace(" ", "_"): This line converts each camelCase key to snake_case. It first converts the key to snake_case using the to_snake_case function recursively. Then, it replaces any spaces (which may occur if the key had a capital letter after a space) with underscores.
    • to_snake_case(value): Recursively converts any nested dictionaries or lists within the value.
  3. List Handling: If the input is a list, the function iterates through each element and applies the to_snake_case function recursively.

Key Advantages:

  • Recursive Approach: The recursive nature allows the function to handle arbitrarily nested dictionaries with ease.
  • Code Clarity: The function is concise and easy to understand, making it maintainable.
  • Flexibility: This solution can be readily adapted to handle other key formatting scenarios.

Further Enhancements:

  • Error Handling: Consider adding error handling for cases where the input might not be a dictionary or list.
  • Key Validation: You could implement additional checks to ensure the input keys adhere to expected camelCase format.

Conclusion:

By leveraging recursion, we can efficiently transform camelCase keys to snake_case within any nested dictionary structure. This approach is versatile, maintainable, and readily adaptable to other key formatting scenarios. With a clear understanding of the logic and its variations, you can effectively handle diverse data structures and seamlessly work with different data formats.

Remember: When dealing with data transformations, choose the approach that best suits your specific needs and context. Recursive solutions, as demonstrated here, can offer a powerful and elegant way to handle complex data structures.