6

我想创建一个“配置”类,它在散列和树之间的某处起作用。它只是用于存储可以有上下文的全局值。

这是我如何使用它:

Config.get("root.parent.child_b") #=> "value"

下面是这个类的样子:

class Construct

  def get(path)
    # split path by "."
    # search tree for nodes
  end

  def set(key, value)
    # split path by "."
    # create tree node if necessary
    # set tree value
  end

  def tree
    {
      :root => {
        :parent => {
          :child_a => "value",
          :child_b => "another value"
        },
        :another_parent => {
          :something => {
            :nesting => "goes on and on"
          }
        }
      }
    }
  end

end

这种东西有没有名字,介于哈希和树之间(不是计算机科学专业)?基本上是树的类似哈希的接口。

像这样输出的东西:

t = TreeHash.new
t.set("root.parent.child_a", "value")
t.set("root.parent.child_b", "another value")

所需的输出格式:

t.get("root.parent.child_a") #=> "value"
t.get("root") #=> {"parent" => {"child_a" => "value", "child_b" => "another value"}}

而不是这个:

t.get("root") #=> nil

或者这个(你可以通过调用获得值{}.value

t.get("root") #=> {"parent" => {"child_a" => {}, "child_b" => {}}}
4

5 回答 5

9

您可以立即实施一个:

class TreeHash < Hash
  attr_accessor :value

  def initialize
    block = Proc.new {|h,k| h[k] = TreeHash.new(&block)}
    super &block
  end

  def get(path)
    find_node(path).value
  end

  def set(path, value)
    find_node(path).value = value
  end

private

  def find_node(path)
    path.split('.').inject(self){|h,k| h[k]}
  end
end

您可以通过将不需要Hash的方法设置为私有方法来改进实现,但它已经按照您想要的方式工作。数据存储在哈希中,因此您可以轻松地将其转换为 yaml。


编辑:

为了满足进一步的期望(并且to_yaml默认正确转换),您应该使用修改后的版本:

class TreeHash < Hash
  def initialize
    block = Proc.new {|h,k| h[k] = TreeHash.new(&block)}
    super &block
  end

  def get(path)
    path.split('.').inject(self){|h,k| h[k]}
  end

  def set(path, value)
    path = path.split('.')
    leaf = path.pop
    path.inject(self){|h,k| h[k]}[leaf] = value
  end
end

此版本稍作权衡,因为您不能将值存储在非叶节点中。

于 2010-06-05T09:46:47.613 回答
1

我认为结构的名称实际上是一个嵌套的 hash,问题中的代码是对 javascript 字典的重新发明。由于 JS(或 Python 或 ...)中的字典可以嵌套,因此每个值都可以是另一个字典,它有自己的键/值对。在 javascript 中,这就是一个对象。

最好的一点是能够使用 JSON 来整齐地定义它,并传递它:

tree : {
  'root' : {
    'parent' : {
      'child_a' : "value",
      'child_b' : "another value"
    },
    'another_parent' : {
      'something' : {
        'nesting' : "goes on and on"
      }
    }
  }
};

然后在 JS 中你可以做 tree.root.parent.child_a。

This answer to another question建议使用Hashie gem将 JSON 对象转换为 Ruby 对象。

于 2011-09-05T05:45:46.357 回答
0

我认为这类似于 TreeMap 数据结构,类似于此处描述的 Java 中的数据结构。它做同样的事情(键/值映射),但检索可能会有所不同,因为您使用节点本身作为键。从描述的 TreeMap 中检索是从实现中抽象出来的,因为当您传入一个键时,您不知道它在树中的确切位置。

希望这是有道理的!

于 2010-06-05T06:18:44.370 回答
0

呃......当然可以使用分层哈希表来完成,但是为什么需要层次结构呢?如果您只需要完全匹配的 get 和 put,为什么不能只创建一个恰好使用点分隔命名约定的哈希表?

这就是实现您所要求的功能所需的全部内容,而且显然非常简单......

于 2010-06-05T07:47:09.650 回答
0

为什么要使用类似哈希的接口?为什么不使用方法链来导航你的树呢?例如config.root.parent.child_b并使用实例方法,如果需要method_missing()实现它们?

于 2010-06-05T08:33:58.043 回答