In Python, I have a dictionary. How do I change the keys of this dictionary?

风格不统一 提交于 2021-02-02 19:55:03

问题


Let's say I have a pretty complex dictionary.

{'fruit':'orange','colors':{'dark':4,'light':5}}

Anyway, my objective is to scan every key in this complex multi-level dictionary. Then, append "abc" to the end of each key.

So that it will be:

{'fruitabc':'orange','colorsabc':{'darkabc':4,'lightabc':5}}

How would you do that?


回答1:


Keys cannot be changed. You will need to add a new key with the modified value then remove the old one, or create a new dict with a dict comprehension or the like.




回答2:


For example like this:

def appendabc(somedict):
    return dict(map(lambda (key, value): (str(key)+"abc", value), somedict.items()))

def transform(multilevelDict):
    new = appendabc(multilevelDict)

    for key, value in new.items():
        if isinstance(value, dict):
            new[key] = transform(value)

    return new

print transform({1:2, "bam":4, 33:{3:4, 5:7}})

This will append "abc" to each key in the dictionary and any value that is a dictionary.

EDIT: There's also a really cool Python 3 version, check it out:

def transform(multilevelDict):
    return {str(key)+"abc" : (transform(value) if isinstance(value, dict) else value) for key, value in multilevelDict.items()}

print(transform({1:2, "bam":4, 33:{3:4, 5:7}}))



回答3:


I use the following utility function that I wrote that takes a target dict and another dict containing the translation and switches all the keys according to it:

def rename_keys(d, keys):
    return dict([(keys.get(k), v) for k, v in d.items()])

So with the initial data:

data = { 'a' : 1, 'b' : 2, 'c' : 3 }
translation = { 'a' : 'aaa', 'b' : 'bbb', 'c' : 'ccc' }

We get the following:

>>> data
{'a': 1, 'c': 3, 'b': 2}
>>> rename_keys(data, translation)
{'aaa': 1, 'bbb': 2, 'ccc': 3}



回答4:


>>> mydict={'fruit':'orange','colors':{'dark':4,'light':5}}

>>> def f(mydict):
...  return dict((k+"abc",f(v) if hasattr(v,'keys') else v) for k,v in mydict.items())
... 
>>> f(mydict)
{'fruitabc': 'orange', 'colorsabc': {'darkabc': 4, 'lightabc': 5}}



回答5:


My understanding is that you can't change the keys, and that you would need to make a new set of keys and assign their values to the ones the original keys were pointing to.

I'd do something like:

def change_keys(d):
  if type(d) is dict:
    return dict([(k+'abc', change_keys(v)) for k, v in d.items()])
  else:
    return d

new_dict = change_keys(old_dict)



回答6:


here's a tight little function:

def keys_swap(orig_key, new_key, d):
    d[new_key] = d.pop(orig_key)

for your particular problem:

def append_to_dict_keys(appendage, d):
    #note that you need to iterate through the fixed list of keys, because
    #otherwise we will be iterating through a never ending key list!
    for each in d.keys():
        if type(d[each]) is dict:
            append_to_dict_keys(appendage, d[each])
        keys_swap(each, str(each) + appendage, d)

append_to_dict_keys('abc', d)



回答7:


#! /usr/bin/env python

d = {'fruit':'orange', 'colors':{'dark':4,'light':5}}

def add_abc(d):
  newd = dict()
  for k,v in d.iteritems():
    if isinstance(v, dict):
      v = add_abc(v)
    newd[k + "abc"] = v
  return newd

d = add_abc(d)
print d



回答8:


Something like that

def applytoallkeys( dic, func ):
    def yielder():
        for k,v in dic.iteritems():
            if isinstance( v, dict):
                yield func(k), applytoallkeys( v, func )
            else:
                yield func(k), v
    return dict(yielder())

def appendword( s ):
    def appender( x ):
        return x+s
    return appender

d = {'fruit':'orange','colors':{'dark':4,'light':5}}
print applytoallkeys( d, appendword('asd') )

I kinda like functional style, you can read just the last line and see what it does ;-)




回答9:


You could do this with recursion:

import collections
in_dict={'fruit':'orange','colors':{'dark':4,'light':5}}

def transform_dict(d):
    out_dict={}
    for k,v in d.iteritems():
        k=k+'abc'
        if isinstance(v,collections.MutableMapping):
            v=transform_dict(v)            
        out_dict[k]=v
    return out_dict
out_dict=transform_dict(in_dict)
print(out_dict)

# {'fruitabc': 'orange', 'colorsabc': {'darkabc': 4, 'lightabc': 5}}



回答10:


you should also consider that there is the possibility of nested dicts in nested lists, which will not be covered by the above solutions. This function ads a prefix and/or a postfix to every key within the dict.

def transformDict(multilevelDict, prefix="", postfix=""):
"""adds a prefix and/or postfix to every key name in a dict"""
new_dict = multilevelDict
if prefix != "" or postfix != "":
    new_key = "%s#key#%s" % (prefix, postfix)
    new_dict = dict(map(lambda (key, value): (new_key.replace('#key#', str(key)), value), new_dict.items()))
    for key, value in new_dict.items():
        if isinstance(value, dict):
            new_dict[key] = transformDict(value, prefix, postfix)
        elif isinstance(value, list):
            for index, item in enumerate(value):
                if isinstance(item, dict):
                    new_dict[key][index] = transformDict(item, prefix, postfix)
return new_dict



回答11:


for k in theDict: theDict[k+'abc']=theDict.pop(k)



回答12:


I use this for converting docopt POSIX-compliant command-line keys to PEP8 keys

(e.g. "--option" --> "option", "" --> "option2", "FILENAME" --> "filename")


arguments = docopt.docopt(__doc__)  # dictionary
for key in arguments.keys():
    if re.match('.*[-<>].*', key) or key != key.lower():
        value = arguments.pop(key)
        newkey = key.lower().translate(None, '-<>')
        arguments[newkey] = value



回答13:


Hi I'm a new user but finding an answer for same question, I can't get anything fully functional to my problem, I make this little piece of cake with a full nested replace of keys, you can send list with dict or dict. Finally your dicts can have list with dict or more dict nested and it is all replaced with your new key needs. To indicate who key want replace with a new key use "to" parameter sending a dict. See at end my little example. P/D: Sorry my bad english. =)

def re_map(value, to):
    """
    Transform dictionary keys to map retrieved on to parameters.
    to parameter should have as key a key name to replace an as value key name
    to new dictionary.
    this method is full recursive to process all levels of
    @param value: list with dictionary or dictionary
    @param to: dictionary with re-map keys
    @type to: dict
    @return: list or dict transformed
    """
    if not isinstance(value, dict):
        if not isinstance(value, list):
            raise ValueError(
                         "Only dict or list with dict inside accepted for value argument.")  # @IgnorePep8

    if not isinstance(to, dict):
        raise ValueError("Only dict accepted for to argument.")

    def _re_map(value, to):
        if isinstance(value, dict):
            # Re map dictionary key.
            # If key of original dictionary is not in "to" dictionary use same
            # key otherwise use re mapped key on new dictionary with already
            # value.
            return {
                    to.get(key) or key: _re_map(dict_value, to)
                    for key, dict_value in value.items()
            }
        elif isinstance(value, list):
            # if value is a list iterate it a call _re_map again to parse
            # values on it.
            return [_re_map(item, to) for item in value]
        else:
            # if not dict or list only return value.
            # it can be string, integer or others.
            return value

    result = _re_map(value, to)

    return result

if __name__ == "__main__":
    # Sample test of re_map method.
    # -----------------------------------------
    to = {"$id": "id"}
    x = []
    for i in range(100):
        x.append({
             "$id": "first-dict",
             "list_nested": [{
                 "$id": "list-dict-nested",
                 "list_dic_nested": [{
                    "$id": "list-dict-list-dict-nested"
                     }]
             }],
             "dict_nested": {
                 "$id": "non-nested"
             }
             })

    result = re_map(x, to)

    print(str(result))



回答14:


A functional (and flexible) solution: this allows an arbitrary transform to be applied to keys (recursively for embedded dicts):

def remap_keys(d, keymap_f):
  """returns a new dict by recursively remapping all of d's keys using keymap_f"""
  return dict([(keymap_f(k), remap_keys(v, keymap_f) if isinstance(v, dict) else v) 
    for k,v in d.items()])

Let's try it out; first we define our key transformation function, then apply it to the example:

def transform_key(key):
  """whatever transformation you'd like to apply to keys"""
  return key + "abc"

remap_keys({'fruit':'orange','colors':{'dark':4,'light':5}}, transform_key)
{'fruitabc': 'orange', 'colorsabc': {'darkabc': 4, 'lightabc': 5}}

(note: if you're still on Python 2.x, you'll need to replace d.items() on the last line with d.iteritems() -- thanks to @Rudy for reminding me to update this post for Python 3).




回答15:


Based on @AndiDog's python 3 version and similar to @sxc731's version but with a flag for whether to apply it recursively:

def transform_keys(dictionary, key_fn, recursive=True):
    """
    Applies function to keys and returns as a new dictionary.

    Example of key_fn:
      lambda k: k + "abc"
    """
    return {key_fn(key): (transform_keys(value, key_fn=key_fn, recursive=recursive)
                          if recursive and isinstance(value, dict) else value)
            for key, value in dictionary.items()}


来源:https://stackoverflow.com/questions/2213334/in-python-i-have-a-dictionary-how-do-i-change-the-keys-of-this-dictionary

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!