Search code examples
arraysjsonrubydata-structuresruby-hash

Convert array with integers which indicate hash depth to hash


I have the following array:

[{text: "a", depth: 0},
 {text: "b", depth: 1},
 {text: "c", depth: 2},
 {text: "d", depth: 1}]

The problem I'm trying to solve is to take a flattened array (above) and create a nested structure based on each element's depth. The reason I need it nested is to build a list (ordered or unordered) recursively which I can't do with the array I have.

The following is in some way, shape, or form the desired output. The general idea for the nested structure I'm trying to create should be clearer.

  { 
    text: "a", 
    depth: 0,
    sublevel: [
      {
        text: "a",
        depth: 1,
        sublevel: [
          {
            text: "b",
            depth: 2,
            sublevel: []
          }
        ]
      },
      {
        text: "d",
        depth: 1,
        sublevel: []
      }
    ]
  }

Solution

  • I figured it out.

    new_structure = []
    depth = 0
    array.each do |element|
      if element[:depth] == 0
        new_structure << element
      else
        if element[:depth] < depth || element[:depth] == depth
          parent = recursive_method(new_structure[-1], element[:depth] - 1)[:sublevel]
          parent = [] if parent.nil?
          parent << element
        else
          recursive_method(new_structure[-1], element[:depth]).merge!({ sublevel: [element] })
        end
      end
      depth = element[:depth]
    end
    
    def recursive_method(structure, depth)
      return structure if structure[:sublevel].nil? || depth == 0
      recursive_method(structure[:sublevel][-1], depth -= 1)
    end
    

    Result:

    [
      {
        :text => "a",
        :depth => 0,
        :sublevel => [
            {
                :text => "b",
                :depth => 1,
                :sublevel => [
                    {
                        :text => "c",
                        :depth => 2
                    }
                ]
            }, 
            {
                :text => "d",
                :depth => 1
            }
        ]
      }
    ]
    

    Open to make it better.