Home
/
Blog
/
For Developers
/
how to change keys and values in a Python dictionary

Interview task: How to change keys and values in a Python dictionary

how to change keys and values in a Python dictionary

There's another task that does a great job of testing your knowledge of dictionaries in Python.

Task:


There's a simple dictionary, for example: my_dict = {'a': 1, 'b': 2, 'c': 3}
 

We need to implement a function that will swap the key and value of the source dictionary.

What do we know about dictionaries in Python?

This is such a data structure for storing information. They are unordered (before Python 3.7) or ordered (since Python 3.7+) collections of items, where each item is stored as a key-value pair.

Seems like a pretty simple task — we take the original dictionary, split the key — value and write it into a new dictionary.

But there's a catch: you'll need to anticipate several cases and talk them through in an interview before doing this task.

1. Key-value pairs: is the fundamental structure of the dictionary. Each element consists of a unique key and its associated value.
 

2. Keys must be unique and hashable. It is not possible for two keys to be identical in the same dictionary. If you try to add a pair with an existing key, the value for that key will be overwritten. Keys must be objects of immutable types for which a hash value can be calculated. This is necessary for fast internal implementation of the search.
 

3. The values can be any. Values in the dictionary can be objects of any data type: numbers, strings, lists, other dictionaries, functions, class objects, etc. One dictionary can contain values of different types.
 

4. Mutable: dictionaries are modifiable.
 

5. Order of elements: till Python 3.6 (including official specification) dictionaries were considered disordered. This meant that the order in which elements were added was not necessarily preserved when iterating over the dictionary or printing it. In the CPython 3.6 implementation (most common) dictionaries became ordered by the fact that the insertion order was preserved, but this was considered an implementation detail that should not be relied upon.

Start with the version Python 3.7, preserving the order in which elements are inserted has become an official part of the language specification. So dictionaries remember the order in which items were added. popitem() also started to delete the last added item (LIFO).
 

6. Quick key access: due to the use of hash tables for internal storage, accessing a value by key, adding a new pair, and deleting a pair is very fast, on average in O(1) (constant time), regardless of the dictionary size. In the worst case (because of hash collisions) it could be O(n).

What will need to be provided (key points to be discussed at the interview)

Hashability of values

  • The keys in a Python dictionary must be hashable.
     
  • The original dictionary values will become the keys within the new dictionary. If there are non- hashed types among values (e.g. lists, other dictionaries, custom objects without без __hash__), then a TypeError will occur when trying to use them as a key.

Solution option: check the type of the value or try to hash(value) it inside the try-except block. If non- hashable, either skip, throw an error (preferred), or attempt a conversion (e.g., list to tuple, if meaningful).
 

Duplicate values in the source dictionary

  • The keys in the dictionary must be unique. If several different keys in the original dictionary have the same value (например, {'a': 1, 'b': 1}), this value (1) will try to become a key twice when inverted.
     
  • Consequences (without special treatment): «The last one to win». In the {'a': 1, 'b': 1} example, the inverted dictionary would be 
    {1: 'b'} (if b is processed later than a), and information about the 'a': 1 pair will be lost.

Solution options:

1. Causing an error ValueError. This is the safest way, as it clearly indicates potential data loss.
 

2. Overwrite (default behavior for dict comprehension). The last value encountered for a given key will overwrite the previous value. This results in loss of data.
 

3. Collect source keys into a list/cortex. If a duplicate value occurs, the new dictionary value for that key becomes a list (or tuple) of all the original keys that had that value. For example, {'a': 1, 'b': 1} turn into {1: ['a', 'b']}. This changes the structure of the resulting dictionary (values become lists), but retains all the information.
 

4. Skip duplicates.
 

Empty dictionary

The function must correctly handle an empty dictionary by returning an empty dictionary.


Return value type

The function is normally expected to return a new dictionary without modifying the original dictionary.

In an interview, it's important not just to write code, but specifically to discuss these points, showing an understanding of the data structure «vocabulary» and potential problems.

The option with dict comprehension ({value: key for key, value in d.items()}) is very concise, but its limitations (silent overwrite on duplicates, less explicit handling of hashing errors) are worth mentioning.

Now let's move on to implementation:
 

def invert_dictionary(*, original_dict: dict) -> dict:
    """
    Swaps keys and values in the dictionary

    Args:
        original_dict (dict): Source vocabulary.

    Returns:
        dict: A new dictionary where values became keys and keys became values.

    Raises:
        TypeError: If any value in the source dictionary is not hashable
                   (e.g., a list) because it cannot be a key.
        ValueError: If there are duplicate values in the source dictionary, that would lead
                   to data loss when inverting (since the keys must be unique).
                    Or you can choose another strategy for handling duplicates.
    """

    inverted_dict = {}
    for key, value in original_dict.items():
        # 1. Checking for hashability of the value (future key)
        try:
            hash(value)
        except TypeError:
            raise TypeError(f"Value'{value}' (from key '{key}') is not hashable and cannot become a key.")

        # 2. Checking for duplicate values (future keys)
        if value in inverted_dict:
            # You can choose a different strategy here:
            # А) Call an error (the safest option to avoid losing data)
			# Б) Overwrite (the last occurrence “wins” - as in dict comprehension)
			# В) Collect the source keys into a list (if allowed by the conditions)
            raise ValueError(
                f"Duplicate value detected '{value}'. "
                f"Keys '{inverted_dict[value]}' and '{key}' both point to this value. "
                f"It is impossible to create unique keys in an inverted dictionary without data loss."
            )
        else:
            inverted_dict[value] = key
            # If strategy В (collecting to a list) is chosen, then the first occurrence must also be a list
            # inverted_dict[value] = [key]
            
    return inverted_dict

# Example of use
my_dict = {'a': 1, 'b': 2, 'c': 3}
try:
    inverted = invert_dictionary(my_dict)
    print(f"Source vocabulary: {my_dict}")
    print(f"Inverted dictionary: {inverted}")
except (TypeError, ValueError) as e:
    print(f"Error: {e}")

print("-" * 20)

# Example with a non- hashed value
dict_with_unhashable = {'a': [1, 2], 'b': 3}
try:
    inverted_unhashable = invert_dictionary(dict_with_unhashable)
    print(f"Inverted (unsuccessful): {inverted_unhashable}")
except (TypeError, ValueError) as e:
    print(f"Source vocabulary: {dict_with_unhashable}")
    print(f"Inversion error: {e}")

print("-" * 20)

# Example with duplicate values
dict_with_duplicates = {'a': 1, 'b': 2, 'c': 1}
try:
    inverted_duplicates = invert_dictionary(dict_with_duplicates)
    print(f"Inverted (unsuccessful): {inverted_duplicates}")
except (TypeError, ValueError) as e:
    print(f"Source vocabulary: {dict_with_duplicates}")
    print(f"Inversion error: {e}")

print("-" * 20)

# A shorter version using dict comprehension (BUT! it silently overwrites for duplicates)
def invert_dictionary_comprehension(original_dict):
    try:
        return {value: key for key, value in original_dict.items()}
    except TypeError as e:
        raise TypeError(f"One of the values is not hashable and cannot be a key. Error Python: {e}")

my_dict_comp = {'x': 10, 'y': 20, 'z': 30}
inverted_comp = invert_dictionary_comprehension(my_dict_comp)
print(f"Initial (comprehension): {my_dict_comp}")
print(f"Inverted (comprehension): {inverted_comp}")

dict_duplicates_comp = {'a': 1, 'b': 2, 'c': 1} # 'a' will overwrite the 'c' for the key 1
inverted_duplicates_comp = invert_dictionary_comprehension(dict_duplicates_comp)
print(f"Original with duplicates (comprehension): {dict_duplicates_comp}")
print(f"Inverted with duplicates (comprehension): {inverted_duplicates_comp}") # {1: 'c', 2: 'b'}
In the implementation variant invert_dictionary_comprehension will silently overwrite values if the original values are duplicated, it does not check for hashability until a key creation is attempted. For an interview, it would be better to show a more elaborate version with checks first.

Questions

Can dict comprehension be used to invert the dictionary?
What if the values in the source dictionary are not hashable?
Does the original vocabulary change when inverting?

Share

Feel free to contact us

Book an appointment

Cases

Tell us about your project
Name
Contact
Message
Attach file +
Request to get files
Name
Send files
Message
Thanks!
Your request has been sent
After processing, our manager will contact you