使用ruby从数组创建嵌套哈希

时间:2018-03-15 12:38:37

标签: arrays ruby hash nested

我试图将数组中的数据重新排列为哈希格式,但是如果使用嵌套,我就会搞砸了

样本数据

[
  ["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"]
]

预期产出

{: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=>[]}]
                         }]
           }]
}

希望我提供明确的解释

PS。编辑以显示我尝试过的内容 首先我制作哈希数组然后做这样的事情 我认为不会混淆这么多

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

2 个答案:

答案 0 :(得分:1)

你可以像这样递归:

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

对于你的数组,它会像这样返回:

# [
# {: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 => []
#             }]
#         }]
#     }]
# }
# ]

答案 1 :(得分:0)

我希望以下代码可以帮助您:

input = [
    ["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"]
  ]

output = Array.new

input.each do |i|
    if output.select { |out| out[:name] == i[0] }.empty?
        output << { :name => i[0], :level => 1, :child => [] }
    end

    level1 = output.select { |out| out[:name] == i[0] }
    level1.each do |l1|
        if l1[:child].select { |l| l[:name] == i[1] }.empty?
            l1[:child] << { :name => i[1], :level => 2, :child => [] }
        end
    end

    level1.each do |l1|
        level2 = l1[:child].select { |l| l[:name] == i[1] }
        level2.each do |l2|
            if l2[:child].select { |l| l[:name] == i[2] }.empty?
                l2[:child] << { :name => i[2], :level => 3, :child => [] } 
            end
        end
    end

    level1.each do |l1|
        level2 = l1[:child].select { |l| l[:name] == i[1] }
        level2.each do |l2|
            level3 = l2[:child].select { |l| l[:name] == i[2] }
            level3.each do |l3|
                if l3[:child].select { |l| l[:name] == i[3] }.empty?
                    l3[:child] << { :name => i[3], :level => 4 } 
                end
            end
        end
    end
end

puts output