【问题标题】:sort a YAML block mapping sequence in python在python中对YAML块映射序列进行排序
【发布时间】:2026-02-11 01:30:01
【问题描述】:

我正在尝试以我想要的方式对 YAML 块映射序列进行排序...我想要类似的东西

depth: !!opencv-matrix
    rows: 480
    cols: 640
    dt: f
    data: 'x'

但每次我做倾销时,它都会变成

cols: 640
    data: 'x'
    depth: !!opencv-matrix
    dt: f
    rows: 480

我在这里检查了一种简单易用的方法

ordering = ['ymlFile','depth', 'rows', 'cols', 'dt', 'data']
ordered_set = [{'depth': '!!opencv-matrix'}, {'rows' : depthSizeImg[0]}, {'cols' : depthSizeImg[1]}, {'dt' : type(img_d[0][0])}, {'data': ymlList.tolist()}]]

f = open(out_d, 'a')
f.write('%YAML:1.0 \n')
f.write(yaml.dump(data, default_flow_style=None, allow_unicode=False, indent = 4))
f.close()

但它使 YAML 不是嵌套的。

%YAML:1.0 
- {depth: '!!opencv-matrix'}
- {rows: 323}
- {cols: 110}
- {dt: !!python/name:numpy.float32 ''}
- {data: 'x'}

我怎样才能得到正确的输出?

【问题讨论】:

  • 我还不得不说,我检查并使用了here 给出的第一个解决方案,但是我收到一条消息,告诉我“ValueError:要解压的值太多”... 关于第二个选项,有人可以告诉我作为翻斗车我可以提供什么参数吗?非常感谢(只是为了澄清......数据不仅仅是一个字符......它是一个我不想放在这里的长 numpy 数组的内容)
  • 我尝试了第二个选项并给了我同样的错误。伙计们,我取决于你和你的想法。

标签: python yaml dump


【解决方案1】:

在你的例子中

ordered_set = [{'depth': '!!opencv-matrix'}, {'rows' : depthSizeImg[0]}, {'cols' : depthSizeImg[1]}, {'dt' : type(img_d[0][0])}, {'data': ymlList.tolist()}]]

你正在转储一个字典列表,这就是你得到的 YAML 输出。调用列表 ordered_set 不会使其成为一个集合,并且在您的数据中包含 YAML 标记(那些 !!object_name 条目)也不会改变它们。

YAML specification 使用 !!omap(示例 2.26)将序列的有序结构与单个键映射组合为元素:

depth: !!omap
  - rows: 480
  - cols: 640
  - dt: f
  - data: x

如果你将它读入 PyYAML,你会得到:

{'depth': [('rows', 480), ('cols', 640), ('dt', 'f'), ('data', 'x')]}

这意味着您无法通过简单的关键字查找获得rows 的值。 如果您将上述内容转储到 YAML,您会变得更加丑陋:

depth:
- !!python/tuple [rows, 480]
- !!python/tuple [cols, 640]
- !!python/tuple [dt, f]
- !!python/tuple [data, x]

如果不定义一些从 !!omap 到有序字典实现和 vv 的映射,您将无法使用 PyYAML 解决这个问题。

您需要为您的 YAML 提供更智能的“Dumper”¹:

import ruamel.yaml as yaml

yaml_str = """\
depth: !!omap
  - rows: 480
  - cols: 640
  - dt: f
  - data: x
"""

data1 = yaml.load(yaml_str)
data1['depth']['data2'] = 'y'
print(yaml.dump(data1, Dumper=yaml.RoundTripDumper))

给出:

depth: !!omap
- rows: 480
- cols: 640
- dt: f
- data: x
- data2: y

或者将其与智能加载器(不会丢弃输入中存在的订购信息)结合使用,您可以省略!!omap

import ruamel.yaml as yaml

yaml_str = """\
depth:
  - rows: 480
  - cols: 640   # my number of columns
  - dt: f
  - data: x
"""

data3 = yaml.load(yaml_str, Loader=yaml.RoundTripLoader)
print(yaml.dump(data3, Dumper=yaml.RoundTripDumper))

给出:

depth:
- rows: 480
- cols: 640     # my number of columns
- dt: f
- data: x

(包括保留的评论)。


¹ 这是使用ruamel.yaml 完成的,我是其中的作者。你应该可以 为了在 PyYAML 中使用 data1 做一些努力,如果没有对 PyYAML 的重大增强,就无法完成另一个示例,这正是 ruamel.yaml 的内容。

【讨论】: