首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Crystal-lang:递归JSON或Hash

Crystal-lang:递归JSON或Hash
EN

Stack Overflow用户
提问于 2020-09-04 08:14:27
回答 1查看 184关注 0票数 1

我正在尝试创建一个可以有N个深度的JSON或Hash。例如:X个名字独特的人可能有Y个孩子,而这些孩子可能有Z个孩子(一直持续到第N代)。我想创建一个Hash (或JSON),如下所示:

代码语言:javascript
复制
{
  "John" => {
              "Lara" => { 
                          "Niko" => "Doe"
                        },
              "Kobe" => "Doe"
            },
  "Jess" => {
              "Alex" => "Patrik"
            }
}

我尝试过使用递归别名,但无法实现。

代码语言:javascript
复制
alias Person = Hash(String, Person) | Hash(String, String)

输入可以来自像这样的字符串数组

代码语言:javascript
复制
["John|Lara|Niko", "John|Kobe", "Jess|Alex"]
["Doe", "Patrik"]

(我可以处理循环。我的问题是将它们添加到Hash中,因为它们的大小未知。)

我遇到了这样的讨论,https://forum.crystal-lang.org/t/how-do-i-create-a-nested-hash-type/885,但不幸的是,我不能实现我想要的,也不能保留Hash的(或JSON的)方法(这是必要的)。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-09-04 18:12:55

我不太明白您是如何从示例输入中得出示例结果的,所以我将使用一个不同的设置:假设我们有一个简单的配置文件格式,其中键是结构化的,并通过点分序列进行分组,所有值都是字符串。

代码语言:javascript
复制
app.name = test
app.mail.enable = true
app.mail.host = mail.local
server.host = localhost
server.port = 3000
log_level = debug

我们可以将其解析为递归Hash,如下所示:

代码语言:javascript
复制
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

输出将为:

代码语言:javascript
复制
config # => {"app" =>
  {"name" => "test", "mail" => {"enable" => "true", "host" => "mail.local"}},
 "server" => {"host" => "localhost", "port" => "3000"},
 "log_level" => "debug"}

或者,我们可以将其解析为递归结构:

代码语言:javascript
复制
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

然后,输出将是:

代码语言:javascript
复制
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"})

递归结构目前没有那么多buggy,为解析的域对象上的自定义方法提供了一个很好的位置,并且通常比递归别名更有前途,递归别名有时会有一点buggy。

Carc.in上的完整示例:https://carc.in/#/r/9mxr

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63733240

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档