Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

creating nested hash from array with ruby

I'm trying to rearrange data in array to be in hash format but I pretty messed up using nested if

Sample Data

[
  ["England", "London", "University College London ", "Faculty of Law"], 
  ["England", "London", "University College London ", "Faculty of Engineering"], 
  ["England", "London", "Imperial College London", "Faculty of Medicine"], 
  ["England", "Manchester", "University of Manchester", "Faculty of Engineering"]
]

Expected Output

{:name=>"England", 
:level=>1, 
:children=>[{:name=>"London", 
             :level=>2, 
             :children=>[{:name=>"University College London ", 
                          :level=>3, 
                          :children=>[{:name=>"Faculty of Law", 
                                       :level=>4, 
                                       :children=>[]},
                                      {:name=>"Faculty of Engineering", 
                                       :level=>4, :children=>[]}]},
                         {:name=>"Imperial College London", 
                          :level=>3, 
                          :children=>[{:name=>"Faculty of Engineering", 
                                       :level=>4, 
                                      :children=>[]}]
                         }]
           }]
}

hope I have provide clear explaination

ps. edit to show what I've tried first i make array of hash then do something like this I thought it wouldn't be confused this much

result = []
arr.each do |b|
  if result.any? {|r| r[:name] == b[:name]}
    if result.first[:children].any? {|r| r[:name] == b[:children].first[:name]}
      if result.first[:children].any?{|c| c[:children].any? {|r| r[:name] == b[:children].first[:children].first[:name] && c[:name] == b[:children].first[:name] }}
        if result.first[:children].any? {|r| r[:children].any? {|c| c[:children].any?{|k| k[:name] == b[:children].first[:children].first[:children].first[:name] && (c[:name] == b[:children].first[:children].first)}}}

        else
          result.first[:children].any?{|c| c[:children].any? {|r| r[:name] == b[:children].first[:children].first[:name] ; r[:children] << b[:children].first[:children].first[:children].first}}

        end #fourth
      else
        result.first[:children].any? {|r| r[:name] == b[:children].first[:name]; r[:children] << b[:children].first[:children].first}
      end 
    else
      result.any? {|r| r[:name] == b[:name] ; r[:children] << b[:children].first}
    end 
  else result << b 
  end
end
like image 639
pepo Avatar asked Apr 17 '26 06:04

pepo


1 Answers

You could do this recursive like this:

def map_objects(array, level = 1)
  new_obj = []
  array.group_by(&:shift).each do |key, val|
    new_obj << {:name=>key, :level=>level, :children=>map_objects(val, level + 1)} if key
  end
  new_obj
end

For your array it will return like this:

# [
# {:name => "England", :level => 1, :children => [
#     {:name => "London", :level => 2, :children => [
#         {:name => "University College London ", :level => 3, :children => [
#             {:name => "Faculty of Law", :level => 4, :children => []
#             },
#             {:name => "Faculty of Engineering", :level => 4, :children => []
#             }]
#         },
#         {:name => "Imperial College London", :level => 3, :children => [
#             {:name => "Faculty of Medicine", :level => 4, :children => []
#             }]
#         }]
#     },
#     {:name => "Manchester", :level => 2, :children => [
#         {:name => "University of Manchester", :level => 3, :children => [
#             {:name => "Faculty of Engineering", :level => 4, :children => []
#             }]
#         }]
#     }]
# }
# ]
like image 75
Lasse Sviland Avatar answered Apr 20 '26 01:04

Lasse Sviland



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!