Search code examples
pythondictionarydictionary-comprehension

Change keys in a dictionary


I have this dictionary.

maximo = {'CodChamado': 50, '_14984|Top Down:': 0, '_14985|Hierarquia solicitante:': 0}

And I want to change these keys "_14984|Top Down:" and "_14985|Hierarquia solicitante:" to

new_key = ['Campo Extra|Top Down:', 'Campo Extra|Hierarquia solicitante:']

The result of that is the new dictionary:

new_maximo = {'CodChamado': 50, 'Campo Extra|Top Down:': 0, 'Campo Extra|Hierarquia solicitante:': 0}

I tried to do this but it doesn't work:

old_key = []
for key in self.maximo:
    if key[0] == "_":
        old_key.append(key)

for i in new_key:
    for j in old_key:
        self.maximo[i] = self.maximo[j]
        del self.maximo[j]

This error appears:

File "<string>", line 3, in <module>
KeyError: '_14984|Top Down:'

Anyone knows how to do it? I need it to be done kind of dynamic because this is not the only dictionary I'm using, but all of the keys I need to change have this pattern with "_" in key[0].


Solution

  • You don't need two loops to do this. If you know the original key, then to get the new key all you need to do is replace the part beginning at "_" and ending at "|" with "Campo Extra|". You can do this using a regular expression like so:

    import re
    
    new_dict = {
        re.sub(r"^_.*?\|", "Campo Extra|", k): v
        for k, v in maximo.items()
    }
    

    Instead of replacing the keys in the original dict, this creates a new dictionary that looks like this:

    {'CodChamado': 50,
     'Campo Extra|Top Down:': 0,
     'Campo Extra|Hierarquia solicitante:': 0}
    

    An explanation of the regex (Try it online):

    ^_.*?\|
    ^        : Start of the string
     _       : An underscore
      .*?    : Zero or more of any character, lazy match
         \|  : A pipe character
    

    If you want to replace the keys in the original dictionary, then you can do it like so:

    for k in list(maximo):
        new_key = re.sub(r"^_.*?\|", "Campo Extra|", k)
        if new_key != k:
            maximo[new_key] = maximo.pop(k)
    

    If you want to avoid regex altogether, then simply replace the call to re.sub with a function that does the same thing:

    def modify_key(k, replacement):
        if k[0] != "_": return k
        try:
            pipe_loc = k.index("|")
            new_k = "Campo Extra" + k[pipe_loc:]
            return new_k
        except ValueError:
            # "|" not found in k
            return k
    
    new_dict = {
        modify_key(k, "Campo Extra"): v
        for k, v in maximo.items()
    }