在YAML中构建简单的层次结构



我正在尝试在YAML中做我认为简单的事情。这是一个具有重复元素的简单层次结构。下面的第一个例子非常接近,但每个节点序列元素都会触发错误:;序列条目的错误缩进";。我看不出它出了什么问题。

注意,我在下面包含了一个有效的示例,但它使用了唯一的键,这不是我想要的。

- agegrp: 1 
- node      : "(14, 6)"
# id: "(14, 6)"
- branch  : "to 7"
id      : "to 7"
tocond  : 7
pr      : 1.0
next    : (0, 0)
- node      : "(14, 7)"
# id: "(14,7)" 
- branch  : "to 7" 
id      : "to 7"
tocond  : 7 
pr      : 0.85 
next    : (0, 0) 
- branch  : "to 8" 
id      : "to 8"
tocond  : 8
pr      :  0.15
next    : (4, 4)
- agegrp      : 2 
- node      : "(14, 6)"
# id: "(14, 6)"
- branch  : "to 7"
id      : "to 7"
tocond  : 7
pr      : 1.0
next    : (0, 0)
- node      : "(14, 7)"
# id: "(14,7)" 
- branch  : "to 7" 
id      : "to 7"
tocond  : 7 
pr      : 0.85 
next    : (0, 0) 
- branch  : "to 8" 
id      : "to 8"
tocond  : 8
pr      :  0.15
next    : (4, 4)

请注意,以下操作有效,但我不希望分支和节点具有唯一的名称。我想要一个重复的结构。我可以在分支和节点前面使用破折号,但这会导致另一个问题:序列条目的缩进不正确。

agegrp:
id: 1
node (14, 6): 
# id: "(14, 6)"
branch: 
id: "to 7"
tocond: 7
pr: 1.0
next: (0, 0)
node (14,7): 
# id: "(14,7)" 
branch to 7: 
id: "to 7"
tocond: 7 
pr: 0.85 
next: (0, 0) 
branch to 8: 
id: "to 8"
tocond: 8
pr:  0.15
next: (4, 4)

将有5个年龄组。节点在年龄组中。分支位于节点内。每个分支有3个属性。我可以在每个节点下使用一个id项,而不是像上面显示的那样。

我对什么时候必须使用前导破折号和什么时候不使用感到困惑。我很困惑什么时候允许一个值,什么时候不允许。

这在YAML中可能吗?TOML不喜欢等级制度。到目前为止,我把它放在csv中,解析它,并用代码构建一个字典。我想我可以使用一种本机表示层次结构的格式。

我想要的输出:

  • 年龄的数组或字典。永远不会超过10个,数组也可以
  • 对于每个年龄组,节点的dict
  • 对于每个节点,分支的数组或dict

这里有一个例子:这里有一条针对年龄组的格言:

(1, 1) =>
CovidSim.Branch(5, 5, 0.2, (2, 1), "nil", "nil")
CovidSim.Branch(5, 6, 0.65, (2, 2), "nil", "mild")
CovidSim.Branch(5, 7, 0.15, (2, 3), "nil", "sick")
(2, 1) =>
CovidSim.Branch(5, 3, 0.8, (0, 0), "nil", "recovered")
CovidSim.Branch(5, 7, 0.2, (3, 3), "nil", "sick")
(2, 2) =>
CovidSim.Branch(6, 6, 1.0, (3, 2), "mild", "mild")
(2, 3) =>
CovidSim.Branch(7, 7, 0.85, (3, 3), "sick", "sick")
CovidSim.Branch(7, 8, 0.15, (3, 4), "sick", "severe")
(3, 2) =>
CovidSim.Branch(6, 3, 1.0, (0, 0), "mild", "recovered")
(3, 3) =>
CovidSim.Branch(7, 3, 0.8, (0, 0), "sick", "recovered")
CovidSim.Branch(7, 7, 0.1, (5, 3), "sick", "sick")
CovidSim.Branch(7, 8, 0.1, (4, 4), "sick", "severe")
(3, 4) =>
CovidSim.Branch(8, 3, 0.45, (0, 0), "severe", "recovered")
CovidSim.Branch(8, 8, 0.5, (4, 4), "severe", "severe")
CovidSim.Branch(8, 4, 0.05, (0, 5), "severe", "dead")
(4, 4) =>
CovidSim.Branch(8, 3, 0.85, (0, 0), "severe", "recovered")
CovidSim.Branch(8, 8, 0.1, (5, 4), "severe", "severe")
CovidSim.Branch(8, 4, 0.05, (0, 5), "severe", "dead")
(5, 3) =>
CovidSim.Branch(7, 3, 0.9, (0, 0), "sick", "recovered")
CovidSim.Branch(7, 4, 0.1, (0, 5), "sick", "dead")
(5, 4) =>
CovidSim.Branch(8, 3, 0.6, (0, 0), "severe", "recovered")
CovidSim.Branch(8, 4, 0.4, (0, 5), "severe", "dead")

外部容器是一个由5个年龄组dict组成的数组。

(注意,这个例子在我减少的每个分支中都包含一些额外的字段。)

谢谢!

如果您查看集合的YAML规范

YAML的块集合对范围使用缩进,并从每个范围开始进入自己的行。

块序列用破折号表示每个条目和空格("-")。

映射使用冒号和空格(":")来标记每个key:值对。

注释以octhorpe开头(也称为"hash"、"sharp"、"pound"或"数字符号"-"#")。

所以你的

- agegrp: 1 

是序列和地图的融合

你可以做一些类似的事情

--- 
- 
id: 1
nodes: 
- 
branches: 
- 
id: "to 7"
next: "(0, 0)"
pr: 1.0
tocond: 7
- 
id: "to 7"
next: "(0, 0)"
pr: 0.85
tocond: 7
- 
id: "to 8"
next: "(4, 4)"
pr: 0.15
tocond: 8
id: "(14, 6)"

如果这符合您的需求

根据您自己的答案:YAML允许您将实体的名称放入YAML文件中。它通过为标签提供语法来做到这一点。下面是一个文件的外观示例:

!agegrp 4:
!node [9,6]:
- !branch
tocond: 6
next:
- 14
- 6
pr: 1.0
!node [9,5]:
- !branch
tocond: 3
next:
- 0
- 0
pr: 0.8
- !branch
tocond: 7
next:
- 14
- 7
pr: 0.2

注意,我使用YAML序列作为节点坐标,因为看起来您无论如何都想将它们解析为数字对((9,6)将被解析为字符串)。你可以保留原来的语法。

这样做的目的是将标签后面的值直接与其关联。因此,4将被标记为!agegrp,序列[9,6]将被标记成!node,包含tocond等的映射将被标记到!branch。像这样的本地标签是应用程序定义的;您将需要在大多数YAML实现中为它们注册处理程序。

从语义上讲,这将把4标记为agegrp(不管是什么),而节点不是agegrpobject的一部分——使用此标记,只有密钥4被标记为agegrp。当然,你如何处理这个文件取决于你自己。另一种选择是:

4: !agegrp
!node [9,6]:
…

现在,包含节点的映射标记为agegrp4只是映射中的一个键(可能解析为整数)。

如果你想让ID成为对象的一部分,你可以将文档转换为基于序列的结构,@KeepCalmAndCarryOn已经展示了实现这一点的常用方法,下面是一个使用标签的方法:

- !agegrp
- !id 4
- !node
- !id [9,6]
- !branch
tocond: 6
next:
- 14
- 6
pr: 1.0
- !node
- !id [9,5]
- !branch
tocond: 3
next:
- 0
- 0
pr: 0.8
- !branch
tocond: 7
next:
- 14
- 7
pr: 0.2

这样做的目的是使节点的内部结构变平,以便ID和分支可以在同一级别上。这需要加载代码在加载该YAML时正确区分!id!branch节点。这种结构通常用于XML中,XML不像YAML那样提供映射,因此,所有嵌套结构都是序列,不同的子级通过其元素名称来区分。

感谢您的帮助。我并没有想到YAML和创建没有任何名称的实体组@KeepCalmAndCarryOn:您的结构生成了一个节点数组,其中一个id项和一个分支项位于同一级别(分支项是分支的数组,每个分支都是属性的dict。这很有效,但显示得不太好,而且更难处理(但肯定包含了我示例中的所有信息)。

我更喜欢严格的等级制度。我手工编码了json。然后,将json解析为嵌套的julia对象:一个dicts数组,如下所示:

Dict{String,Any} with 5 entries:
"4" => Dict{String,Any}("(9,6)"=>Any[Dict{String,Any}("tocond"=>6,"next"=>Any…
"1" => Dict{String,Any}("(9,6)"=>Any[Dict{String,Any}("tocond"=>6,"next"=>Any…
"5" => Dict{String,Any}("(9,6)"=>Any[Dict{String,Any}("tocond"=>6,"next"=>Any…
"2" => Dict{String,Any}("(9,6)"=>Any[Dict{String,Any}("tocond"=>6,"next"=>Any…
"3" => Dict{String,Any}("(9,6)"=>Any[Dict{String,Any}("tocond"=>6,"next"=>Any…

输出被截断,但您可以将每个年龄组视为一个键,并将节点的dict作为其值。每个节点dict显示第一个键(一个节点),其值为一个分支数组。分支数组中的每个项都是分支的每个属性的字段的dict。

一个agegrp看起来像这样:

Dict{String,Any} with 8 entries:
"(9,6)"  => Any[Dict{String,Any}("tocond"=>6,"next"=>Any[14, 6],"pr"=>1.0)]
"(9,5)"  => Any[Dict{String,Any}("tocond"=>3,"next"=>Any[0, 0],"pr"=>0.8), Di…
"(14,6)" => Any[Dict{String,Any}("tocond"=>3,"next"=>Any[0, 0],"pr"=>1.0)]
"(9,7)"  => Any[Dict{String,Any}("tocond"=>7,"next"=>Any[14, 7],"pr"=>0.85), …
"(5,5)"  => Any[Dict{String,Any}("tocond"=>5,"next"=>Any[9, 5],"pr"=>0.2), Di…
"(14,8)" => Any[Dict{String,Any}("tocond"=>3,"next"=>Any[0, 0],"pr"=>0.45), D…
"(14,7)" => Any[Dict{String,Any}("tocond"=>3,"next"=>Any[0, 0],"pr"=>0.85), D…
"(19,8)" => Any[Dict{String,Any}("tocond"=>3,"next"=>Any[0, 0],"pr"=>0.9), Di…

然后,我取了这个Julia嵌套对象(有点粗糙,但结构更清晰——至少对我来说是这样),并将其通过YAML来创建有效的YAML输出。

这个YAML正是我真正想要的,即使对于正确使用YAML的人来说它看起来很恶心。这里只有一个agegrp(其他的结构相同,在YAML文档中按顺序排列):

4:                     # the id of an agegrp
(9,6):               # the id of a node
- tocond: 6        # first property of a branch
next:
- 14
- 6
pr: 1.0
(9,5):
- tocond: 3
next:
- 0
- 0
pr: 0.8
- tocond: 7
next:
- 14
- 7
pr: 0.2
(14,6):
- tocond: 3
next:
- 0
- 0
pr: 1.0
(9,7):
- tocond: 7
next:
- 14
- 7
pr: 0.85
- tocond: 8
next:
- 14
- 8
pr: 0.15
<rest of output truncated...>

这遵循了我想要的层次结构:

top: an agegroup id
then a node (with more following after the indented children)
then a branch
then an array of the branches properties

我把实体的名称(agegrp、node、branch)与每个实体的特定实例的实际值混合在一起,真的把自己搞砸了——就像我试图用它的类型来标记每件事一样。在Dict中你不会这么做。我在这里使用Julia,但Dict本质上与Python中的相同。

因此,对YAML的尝试有点令人沮丧。但是,它将比我开始使用的CSV更容易输入,也比手工编写JSON更容易。所以,一次成功的尝试!

相关内容

最新更新