Crystal-lang:递归JSON或Hash
Crystal-lang: Recursive JSON or Hash
我正在尝试创建一个 JSON 或可以具有 N 深度的哈希。
例子:
X 人有独特的名字可能有 Y 个孩子,而那些孩子可能有 Z 个孩子(并持续到 N 代)。
我想创建一个如下所示的哈希(或 JSON):
{
"John" => {
"Lara" => {
"Niko" => "Doe"
},
"Kobe" => "Doe"
},
"Jess" => {
"Alex" => "Patrik"
}
}
我尝试使用递归别名,但无法实现。
alias Person = Hash(String, Person) | Hash(String, String)
输入可以来自字符串数组,例如
["John|Lara|Niko", "John|Kobe", "Jess|Alex"]
["Doe", "Patrik"]
(我可以处理循环。我的问题是将它们添加到哈希中,因为它们的大小未知。)
我遇到了这个讨论 https://forum.crystal-lang.org/t/how-do-i-create-a-nested-hash-type/885 但不幸的是我无法实现我想要的并且也无法保留哈希(或 JSON 的)方法(这是必需的)。
我不太明白你是如何从你的示例输入中得到你的示例结果的,所以我将使用不同的设置:假设我们有一个简单的配置文件格式,其中的键是结构化和分组的通过虚线序列,所有值始终是字符串。
app.name = test
app.mail.enable = true
app.mail.host = mail.local
server.host = localhost
server.port = 3000
log_level = debug
我们可以像这样将其解析为递归 Hash
:
alias ParsedConfig = Hash(String, ParsedConfig)|String
config = Hash(String, ParsedConfig).new
# CONFIG being our input from above
CONFIG.each_line do |entry|
keys, value = entry.split(" = ")
keys = keys.split(".")
current = config
keys[0..-2].each do |key|
if current.has_key?(key)
item = current[key]
if item.is_a?(Hash)
current = item
else
raise "Malformed config"
end
else
item = Hash(String, ParsedConfig).new
current[key] = item
current = item
end
end
current[keys.last] = value
end
pp! config
输出将是:
config # => {"app" =>
{"name" => "test", "mail" => {"enable" => "true", "host" => "mail.local"}},
"server" => {"host" => "localhost", "port" => "3000"},
"log_level" => "debug"}
或者我们可以将其解析为递归结构:
record ConfigGroup, entries = Hash(String, ConfigGroup|String).new
config = ConfigGroup.new
# CONFIG being our input from above
CONFIG.each_line do |entry|
keys, value = entry.split(" = ")
keys = keys.split(".")
current = config
keys[0..-2].each do |key|
if current.entries.has_key?(key)
item = current.entries[key]
if item.is_a?(ConfigGroup)
current = item
else
raise "Malformed config"
end
else
item = ConfigGroup.new
current.entries[key] = item
current = item
end
end
current.entries[keys.last] = value
end
pp! config
然后输出将是:
config # => ConfigGroup(
@entries=
{"app" =>
ConfigGroup(
@entries=
{"name" => "test",
"mail" =>
ConfigGroup(@entries={"enable" => "true", "host" => "mail.local"})}),
"server" => ConfigGroup(@entries={"host" => "localhost", "port" => "3000"}),
"log_level" => "debug"})
递归结构目前的错误较少,为您解析的域对象上的自定义方法提供了一个很好的地方,并且通常比递归别名有更确定的未来,递归别名有时有点错误。
carc.in 上的完整示例:https://carc.in/#/r/9mxr
我正在尝试创建一个 JSON 或可以具有 N 深度的哈希。 例子: X 人有独特的名字可能有 Y 个孩子,而那些孩子可能有 Z 个孩子(并持续到 N 代)。 我想创建一个如下所示的哈希(或 JSON):
{
"John" => {
"Lara" => {
"Niko" => "Doe"
},
"Kobe" => "Doe"
},
"Jess" => {
"Alex" => "Patrik"
}
}
我尝试使用递归别名,但无法实现。
alias Person = Hash(String, Person) | Hash(String, String)
输入可以来自字符串数组,例如
["John|Lara|Niko", "John|Kobe", "Jess|Alex"]
["Doe", "Patrik"]
(我可以处理循环。我的问题是将它们添加到哈希中,因为它们的大小未知。)
我遇到了这个讨论 https://forum.crystal-lang.org/t/how-do-i-create-a-nested-hash-type/885 但不幸的是我无法实现我想要的并且也无法保留哈希(或 JSON 的)方法(这是必需的)。
我不太明白你是如何从你的示例输入中得到你的示例结果的,所以我将使用不同的设置:假设我们有一个简单的配置文件格式,其中的键是结构化和分组的通过虚线序列,所有值始终是字符串。
app.name = test
app.mail.enable = true
app.mail.host = mail.local
server.host = localhost
server.port = 3000
log_level = debug
我们可以像这样将其解析为递归 Hash
:
alias ParsedConfig = Hash(String, ParsedConfig)|String
config = Hash(String, ParsedConfig).new
# CONFIG being our input from above
CONFIG.each_line do |entry|
keys, value = entry.split(" = ")
keys = keys.split(".")
current = config
keys[0..-2].each do |key|
if current.has_key?(key)
item = current[key]
if item.is_a?(Hash)
current = item
else
raise "Malformed config"
end
else
item = Hash(String, ParsedConfig).new
current[key] = item
current = item
end
end
current[keys.last] = value
end
pp! config
输出将是:
config # => {"app" =>
{"name" => "test", "mail" => {"enable" => "true", "host" => "mail.local"}},
"server" => {"host" => "localhost", "port" => "3000"},
"log_level" => "debug"}
或者我们可以将其解析为递归结构:
record ConfigGroup, entries = Hash(String, ConfigGroup|String).new
config = ConfigGroup.new
# CONFIG being our input from above
CONFIG.each_line do |entry|
keys, value = entry.split(" = ")
keys = keys.split(".")
current = config
keys[0..-2].each do |key|
if current.entries.has_key?(key)
item = current.entries[key]
if item.is_a?(ConfigGroup)
current = item
else
raise "Malformed config"
end
else
item = ConfigGroup.new
current.entries[key] = item
current = item
end
end
current.entries[keys.last] = value
end
pp! config
然后输出将是:
config # => ConfigGroup(
@entries=
{"app" =>
ConfigGroup(
@entries=
{"name" => "test",
"mail" =>
ConfigGroup(@entries={"enable" => "true", "host" => "mail.local"})}),
"server" => ConfigGroup(@entries={"host" => "localhost", "port" => "3000"}),
"log_level" => "debug"})
递归结构目前的错误较少,为您解析的域对象上的自定义方法提供了一个很好的地方,并且通常比递归别名有更确定的未来,递归别名有时有点错误。
carc.in 上的完整示例:https://carc.in/#/r/9mxr