6

ハッシュとツリーの間のどこかで機能する「Config」クラスを作成したいと思います。これは、コンテキストを持つことができるグローバル値を格納するためだけのものです。

これが私がそれを使う方法です:

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

構造の名前は実際にはネストされたハッシュであり、問​​題のコードは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

これは、ここで説明するJavaのデータ構造に似たTreeMapデータ構造に似ていると思います。同じこと(キー/値のマッピング)を実行しますが、ノード自体をキーとして使用しているため、取得が異なる場合があります。説明されているTreeMapからの取得は、キーを渡すときにツリー内のキーの正確な位置がわからないため、実装から抽象化されています。

それが理にかなっていることを願っています!

于 2010-06-05T06:18:44.370 に答える
0

なぜハッシュのようなインターフェースを使用するのですか? メソッドの連鎖を使用してツリーをナビゲートしてみませんか? たとえばconfig.root.parent.child_b、インスタンスメソッドを使用し、必要に応じmethod_missing()てそれらを実装しますか?

于 2010-06-05T08:33:58.043 に答える
0

ええと... 階層型ハッシュ テーブルを使用すれば確かに実行できますが、なぜ階層型が必要なのですか? 正確に一致する get と put のみが必要な場合、たまたまドット区切りの命名規則を使用する単一のハッシュ テーブルを作成できないのはなぜですか?

要求した機能を実装するために必要なのはそれだけであり、明らかに非常に簡単です...

于 2010-06-05T07:47:09.650 に答える