Rename a dictionary key

后端 未结 12 744
盖世英雄少女心
盖世英雄少女心 2020-11-22 16:54

Is there a way to rename a dictionary key, without reassigning its value to a new name and removing the old name key; and without iterating through dict key/value?

I

相关标签:
12条回答
  • 2020-11-22 17:46

    For a regular dict, you can use:

    mydict[k_new] = mydict.pop(k_old)
    

    This will move the item to the end of the dict, unless k_new was already existing in which case it will overwrite the value in-place.

    For a Python 3.7+ dict where you additionally want to preserve the ordering, the simplest is to rebuild an entirely new instance. For example, renaming key 2 to 'two':

    >>> d = {0:0, 1:1, 2:2, 3:3}
    >>> {"two" if k == 2 else k:v for k,v in d.items()}
    {0: 0, 1: 1, 'two': 2, 3: 3}
    

    The same is true for an OrderedDict, where you can't use dict comprehension syntax, but you can use a generator expression:

    OrderedDict((k_new if k == k_old else k, v) for k, v in od.items())
    

    Modifying the key itself, as the question asks for, is impractical because keys are hashable which usually implies they're immutable and can't be modified.

    0 讨论(0)
  • 2020-11-22 17:46

    In Python 3.6 (onwards?) I would go for the following one-liner

    test = {'a': 1, 'old': 2, 'c': 3}
    old_k = 'old'
    new_k = 'new'
    new_v = 4  # optional
    
    print(dict((new_k, new_v) if k == old_k else (k, v) for k, v in test.items()))
    

    which produces

    {'a': 1, 'new': 4, 'c': 3}
    

    May be worth noting that without the print statement the ipython console/jupyter notebook present the dictionary in an order of their choosing...

    0 讨论(0)
  • 2020-11-22 17:49

    In case someone wants to rename all the keys at once providing a list with the new names:

    def rename_keys(dict_, new_keys):
        """
         new_keys: type List(), must match length of dict_
        """
    
        # dict_ = {oldK: value}
        # d1={oldK:newK,} maps old keys to the new ones:  
        d1 = dict( zip( list(dict_.keys()), new_keys) )
    
              # d1{oldK} == new_key 
        return {d1[oldK]: value for oldK, value in dict_.items()}
    
    0 讨论(0)
  • 2020-11-22 17:50

    A few people before me mentioned the .pop trick to delete and create a key in a one-liner.

    I personally find the more explicit implementation more readable:

    d = {'a': 1, 'b': 2}
    v = d['b']
    del d['b']
    d['c'] = v
    

    The code above returns {'a': 1, 'c': 2}

    0 讨论(0)
  • 2020-11-22 17:51

    I came up with this function which does not mutate the original dictionary. This function also supports list of dictionaries too.

    import functools
    from typing import Union, Dict, List
    
    
    def rename_dict_keys(
        data: Union[Dict, List[Dict]], old_key: str, new_key: str
    ):
        """
        This function renames dictionary keys
    
        :param data:
        :param old_key:
        :param new_key:
        :return: Union[Dict, List[Dict]]
        """
        if isinstance(data, dict):
            res = {k: v for k, v in data.items() if k != old_key}
            try:
                res[new_key] = data[old_key]
            except KeyError:
                raise KeyError(
                    "cannot rename key as old key '%s' is not present in data"
                    % old_key
                )
            return res
        elif isinstance(data, list):
            return list(
                map(
                    functools.partial(
                        rename_dict_keys, old_key=old_key, new_key=new_key
                    ),
                    data,
                )
            )
        raise ValueError("expected type List[Dict] or Dict got '%s' for data" % type(data))
    
    0 讨论(0)
  • 2020-11-22 17:54

    Suppose you want to rename key k3 to k4:

    temp_dict = {'k1':'v1', 'k2':'v2', 'k3':'v3'}
    temp_dict['k4']= temp_dict.pop('k3')
    
    0 讨论(0)
提交回复
热议问题