2010-06-05 1 views
6

해시와 트리 사이에서 작동하는 "구성"클래스를 만들고 싶습니다. 컨텍스트를 가질 수있는 전역 값을 저장하기위한 것입니다. 여기Hash-Like/Tree와 같은 Construct Called는 무엇입니까?

이다 나는 그것을 사용하는 방법 :

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 

는 이런 종류의 이름이 거기에 (어딘가에 해시와 나무 사이에하는하지 :

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

가 같은 클래스가 보일 수 있습니다 무엇 컴퓨터 과학 전공)? 기본적으로 나무에 대한 해시 같은 인터페이스. 이렇게 출력

예시 :

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" => {}}} 

답변

8

당신이없는 시간에 일을 구현할 수 있습니다. 데이터는 해시에 저장되므로 쉽게 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 

이 버전으로, 약간의 절충입니다 잎이 아닌 노드에는 값을 저장할 수 없습니다.

+0

이것은 굉장합니다. –

+0

어떤 아이디어를 추가하는 방법 a) 리프 노드는 해시가 아니며, 값 (기본적으로'attr_accessor : value'를 제거하는 것을 의미 함)과 b)'get ("root")'또는 어떤 레벨 반환 잎 노드가 아닌 경우 아래의 트리가 null 대신? 이를 구현하려고 시도하지만 많은 코드/복잡성을 추가하고 있습니다. 아마 하나의 라이너 트릭을 알고있을 것입니다. 샘플 출력으로 질문을 업데이트했습니다. –

+0

나는 코드를 제거하는 대신에 다음을 추가하는 대신에 – samuil

0

이 생각은 here과 같은 Java의 TreeMap 데이터 구조와 유사하다고 생각합니다. 동일한 작업 (키/값 매핑)을 수행하지만 노드 자체를 키로 사용하므로 검색이 다를 수 있습니다. 설명 된 TreeMap에서 가져 오는 것은 구현에서 추상화됩니다. 키를 전달하면 트리에서 트리의 정확한 위치를 알 수 없기 때문입니다.

희망이 맞습니다!

0

어 ... 확실히 계층 적 해시 테이블을 사용하여 수행 할 수 있지만 계층 구조가 필요한 이유는 무엇입니까? 정확히 일치하는 get 및 put 만 필요하면 왜 점으로 구분 된 명명 규칙을 사용하는 단일 해시 테이블을 만들 수 없습니까?

모두가 당신이 요구 한 기능을 구현하는 데 필요한, 그리고 그것은 분명히 매우 간단이야이야

...

+0

yaml을 사용하여이 모든 것을 정의하고 모든 레벨에서 하위 노드를 검색 할 수 있지만 동시에 데이터베이스에이 노드를 저장하고 최종 사용자가 사용자 정의 할 수있게하려고합니다. 궁극적으로 결국에는 나무가 아닐까요? –

0

이유는 전혀 해시와 같은 인터페이스를 사용합니까? 왜 당신의 나무를 탐색하는 방법의 체인을 사용하지 않습니까? 예를 들어 config.root.parent.child_b을 사용하고 인스턴스 메소드를 사용하고 필요하다면 method_missing()을 구현하면됩니까?

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 방법을 설정하여 구현을 향상시킬 수 있지만, 이미 당신이 그것을 원하는 방식으로 작동 :

+0

너무 복잡해, 나는 어떤 경험 수준의 사람이라도 이것을 사용할 수 있기를 바라고있다. 점으로 구분 된 문자열이있는 해시는 이해하기 쉽습니다. 중첩 된 객체/클래스는 새 코너에 대해 사용자 정의하기가 더 복잡하고 어렵습니다. –

1

구조체의 이름은 실제로 중첩 된 해시이며이 코드는 자바 스크립트의 사전을 재 변조 한 것입니다. JS (또는 Python 또는 ...)의 사전은 중첩 될 수 있으므로 각 값은 고유 한 키/val 쌍이있는 다른 사전이 될 수 있습니다. 자바 스크립트에서는 그게 전부 객체입니다.

그리고 최고의 비트는 깔끔하게을 정의하는 JSON을 사용하고, 그것을 주변에 통과 할 수있는됩니다 : 당신이 다음 tree.root.parent.child_a을 할 수있는 JS에서

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

합니다.

This answer to another questionHashie gem을 사용하여 JSON 객체를 Ruby 객체로 변환 할 것을 제안합니다.