如何在从YAML文档加载的Python字典中的指定位置插入键值对?
例如,如果字典是:
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
我希望在'Age'
之前,'Name'
之后插入元素'Phone':'1234'
。我将要处理的实际字典非常大(解析的YAML文件),因此删除和重新插入可能有点麻烦(我不是很确定)。
如果我能够找到一种在OrderedDict
中插入到指定位置的方法,那也可以。
如何在从YAML文档加载的Python字典中的指定位置插入键值对?
例如,如果字典是:
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
我希望在'Age'
之前,'Name'
之后插入元素'Phone':'1234'
。我将要处理的实际字典非常大(解析的YAML文件),因此删除和重新插入可能有点麻烦(我不是很确定)。
如果我能够找到一种在OrderedDict
中插入到指定位置的方法,那也可以。
遇到了同样的问题,按照下面的方式解决,不需要任何额外的导入,只需要几行代码即可。已在Python 3.6.9中测试通过。
mydict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
print(mydict)
# {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
pos = list(mydict.keys()).index('Age')
items = list(mydict.items())
items.insert(pos, ('Phone', '123-456-7890'))
mydict = dict(items)
print(mydict)
# {'Name': 'Zara', 'Phone': '123-456-7890', 'Age': 7, 'Class': 'First'}
编辑于2021年12月20日:
刚刚发现ruamel.yaml提供了一个insert方法,可以看一下该项目页面上的示例:
import sys
from ruamel.yaml import YAML
yaml_str = """\
first_name: Art
occupation: Architect # This is an occupation comment
about: Art Vandelay is a fictional character that George invents...
"""
yaml = YAML()
data = yaml.load(yaml_str)
data.insert(1, 'last name', 'Vandelay', comment="new key")
yaml.dump(data, sys.stdout)
any
类型,这使得VSCode无法在没有类型声明的情况下找到CommentedMap.insert()
方法的签名。因此,我在这里提供了源代码的链接:https://github.com/commx/ruamel-yaml/blob/a1b222e22a20365b2a338b0281f4b8c2b133da7e/comments.py#L882。如果您想要添加类型声明,可以通过`from ruamel.yaml.comments import CommentedMap`进行导入。 - Swirle13mykeys = ['Name', 'Age', 'Class']
mydict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'} # order doesn't matter
k, v = 'Phone', '123-456-7890'
mykeys.insert(mykeys.index('Name')+1, k)
mydict[k] = v
for k in mykeys:
print(f'{k} => {mydict[k]}')
# Name => Zara
# Phone => 123-456-7890
# Age => 7
# Class => First
collections.OrderedDict
结构,它会维护插入的顺序。from collections import OrderedDict
data = [('Name', 'Zara'), ('Phone', '1234'), ('Age', 7), ('Class', 'First')]
odict = OrderedDict(data)
odict
# OrderedDict([('Name', 'Zara'),
# ('Phone', '1234'),
# ('Age', 7),
# ('Class', 'First')])
OrderedDict
不支持在任意位置插入元素(它只会记住将键插入字典的顺序)。dictAsList = [(k, v) for k, v in yourDict.items()]
。现在,您只需要遍历dictAsList
并在需要的位置插入您的项目即可。 - cs95RoundTripLoader
,你将不能保留从YAML文档中获得的键顺序。如果你想要保留顺序,最好使用RoundTripLoader
,它是专门为此目的而设计的(除其他之外)。 - Anthon你需要将字典初始化为OrderedDict。创建一个新的空OrderedDict,遍历原始字典的所有键,当键名匹配时,在前面/后面插入。
from pprint import pprint
from collections import OrderedDict
def insert_key_value(a_dict, key, pos_key, value):
new_dict = OrderedDict()
for k, v in a_dict.items():
if k==pos_key:
new_dict[key] = value # insert new key
new_dict[k] = v
return new_dict
mydict = OrderedDict([('Name', 'Zara'), ('Age', 7), ('Class', 'First')])
my_new_dict = insert_key_value(mydict, "Phone", "Age", "1234")
pprint(my_new_dict)
dict
会保持插入顺序,因此不需要使用OrderedDict
。 - user3064538这是对nurp答案的跟进。它对我起作用了,但不带任何保修。
# Insert dictionary item into a dictionary at specified position:
def insert_item(dic, item={}, pos=None):
"""
Insert a key, value pair into an ordered dictionary.
Insert before the specified position.
"""
from collections import OrderedDict
d = OrderedDict()
# abort early if not a dictionary:
if not item or not isinstance(item, dict):
print('Aborting. Argument item must be a dictionary.')
return dic
# insert anywhere if argument pos not given:
if not pos:
dic.update(item)
return dic
for item_k, item_v in item.items():
for k, v in dic.items():
# insert key at stated position:
if k == pos:
d[item_k] = item_v
d[k] = v
return d
d = {'A':'letter A', 'C': 'letter C'}
insert_item(['A', 'C'], item={'B'})
## Aborting. Argument item must be a dictionary.
insert_item(d, item={'B': 'letter B'})
## {'A': 'letter A', 'C': 'letter C', 'B': 'letter B'}
insert_item(d, pos='C', item={'B': 'letter B'})
# OrderedDict([('A', 'letter A'), ('B', 'letter B'), ('C', 'letter C')])
def add_item(d, new_pair, old_key): #insert a newPair (key, value) after old_key
n=list(d.keys()).index(old_key)
return {key:d.get(key,new_pair[1]) for key in list(d.keys())[:n+1] +[new_pair[0]] + list(d.keys())[n+1:] }
输入:new_pair=('Phone',1234) , old_key='Age'
输出:{'Name': 'Zara', 'Age': 7, 'Phone': 1234, 'Class': 'First'}
简单可重现的示例(使用 zip()
进行解包和打包)
### Task - Insert 'Bangladesh':'Dhaka' after 'India' in the capitals dictinary
## Given dictionary
capitals = {'France':'Paris', 'United Kingdom':'London', 'India':'New Delhi',
'United States':'Washington DC','Germany':'Berlin'}
## Step 1 - Separate into 2 lists containing : 1) keys, 2) values
country, cap = (list(tup) for tup in zip(*capitals.items()))
# or
country, cap = list(map(list, zip(*capitals.items())))
print(country)
#> ['France', 'United Kingdom', 'India', 'United States', 'Germany']
print(cap)
#> ['Paris', 'London', 'New Delhi', 'Washington DC', 'Berlin']
## Step 2 - Find index of item before the insertion point (from either of the 2 lists)
req_pos = country.index('India')
print(req_pos)
#> 2
## Step 3 - Insert new entry at specified position in both lists
country.insert(req_pos+1, 'Bangladesh')
cap.insert(req_pos+1, 'Dhaka')
print(country)
#> ['France', 'United Kingdom', 'India', 'Bangladesh', 'United States', 'Germany']
print(cap)
#> ['Paris', 'London', 'New Delhi', 'Dhaka', 'Washington DC', 'Berlin']
## Step 4 - Zip up the 2 lists into a dictionary
capitals = dict(zip(country, cap))
print(capitals)
#> {'France': 'Paris', 'United Kingdom': 'London', 'India': 'New Delhi', 'Bangladesh': 'Dhaka', 'United States': 'Washington DC', 'Germany': 'Berlin'}
一旦您使用了load()
(没有选项Loader=RoundTripLoader
),并且您的数据在dict()
中,那么为时已晚,因为YAML文件中可用的顺序通常已经消失了(顺序取决于实际使用的键、使用的Python(实现、版本和可能的编译选项)。
您需要做的是使用round_trip_load()
:
import sys
from ruamel import yaml
yaml_str = "{'Name': 'Zara', 'Age': 7, 'Class': 'First'}"
data = yaml.round_trip_load(yaml_str)
pos = list(data.keys()).index('Age') # determine position of 'Age'
# insert before position of 'Age'
data.insert(pos, 'Phone', '1234', comment='This is the phone number')
data.fa.set_block_style() # I like block style
yaml.round_trip_dump(data, sys.stdout)
这将不可避免地给出:
Name: Zara
Phone: '1234' # This is the phone number
Age: 7
Class: First
在幕后,round_trip_dump()
会透明地为您提供 orderddict
的子类,以使这一切成为可能(其实际实现取决于您的 Python 版本)。
由于您的元素是成对出现的,我认为这个方法可能有效。
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
new_element = { 'Phone':'1234'}
dict = {**dict,**new_element}
print(dict)
{'Name': 'Zara', 'Age': 7, 'Class': 'First', 'Phone': '1234'}