Ответ 1
Ключи не могут быть изменены. Вам нужно будет добавить новый ключ с измененным значением, затем удалить старый или создать новый dict с пониманием dict или т.п.
Скажем, у меня довольно сложный словарь.
{'fruit':'orange','colors':{'dark':4,'light':5}}
В любом случае, моя цель - сканировать каждый ключ в этом сложном многоуровневом словаре. Затем добавьте "abc" в конец каждой клавиши.
Итак, это будет:
{'fruitabc':'orange','colorsabc':{'darkabc':4,'lightabc':5}}
Как вы это сделаете?
Ключи не могут быть изменены. Вам нужно будет добавить новый ключ с измененным значением, затем удалить старый или создать новый dict с пониманием dict или т.п.
Например, например:
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}})
Это добавит "abc" к каждой клавише словаря и любому значению, которое является словарем.
EDIT: Там также действительно классная версия Python 3, проверьте:
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}}))
>>> 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}}
Я понимаю, что вы не можете изменить ключи и вам нужно будет создать новый набор ключей и присвоить их значения тем, на которые указывали оригинальные клавиши.
Я бы сделал что-то вроде:
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)
Я использую следующую служебную функцию, которую я написал, которая принимает целевой dict и другой dict, содержащий перевод, и переключает все ключи в соответствии с ним:
def rename_keys(d, keys):
return dict([(keys.get(k), v) for k, v in d.items()])
Итак, с исходными данными:
data = { 'a' : 1, 'b' : 2, 'c' : 3 }
translation = { 'a' : 'aaa', 'b' : 'bbb', 'c' : 'ccc' }
Получаем следующее:
>>> data
{'a': 1, 'c': 3, 'b': 2}
>>> rename_keys(data, translation)
{'aaa': 1, 'bbb': 2, 'ccc': 3}
#! /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
Что-то вроде этого
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') )
Мне нравится функциональный стиль, вы можете прочитать только последнюю строку и посмотреть, что она делает; -)
здесь плотная небольшая функция:
def keys_swap(orig_key, new_key, d):
d[new_key] = d.pop(orig_key)
для вашей конкретной проблемы:
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)
Вы можете сделать это с помощью рекурсии:
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}}
вы также должны учитывать, что существует возможность вложенных dicts во вложенных списках, которые не будут покрыты вышеупомянутыми решениями. Эта функция объявляет префикс и/или постфикс для каждой клавиши в 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
for k in theDict: theDict[k+'abc']=theDict.pop(k)
Я использую это для преобразования docopt POSIX-совместимых ключей командной строки в ключи PEP8
(например, "--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
Привет, Я новый пользователь, но нахожу ответ на тот же вопрос, я не могу получить что-то полностью функциональное для моей проблемы, я делаю этот маленький кусок пирога с полной вложенной заменой ключей, вы можете отправить список с помощью dict или dict. Наконец, ваши dicts могут иметь список с dict или more dict вложенным, и все это заменяется вашими новыми потребностями. Чтобы указать, какой ключ нужно заменить новым ключом, используйте параметр "to", отправляющий dict. В конце мой маленький пример. P/D: Извините, мой плохой английский. =)
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))
Функциональное (и гибкое) решение: это позволяет применять произвольное преобразование к ключам (рекурсивно для встроенных диктов):
def remap_keys(d, keymap_f):
"""returns a new dict by recursively remapping all of d 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()])
Давай попробуем; сначала мы определяем нашу функцию преобразования ключей, а затем применяем ее к примеру:
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}}
(примечание: если вы все еще используете Python 2.x, вам нужно заменить d.items()
в последней строке на d.iteritems()
- спасибо @Rudy за напоминание о необходимости обновить этот пост для Python 3).