有没有更好的方法在Ruby中重组这个数组?

时间:2016-03-31 16:18:11

标签: arrays ruby

我有一个看起来像这样的数组:

{
    year_list: [{
        name: 2016,
        make_list: [{
            name: 'Honda',
            model_list: [{
                name: 'CRV',
                series_list: [{
                    name: 'Premium Plus',
                    style_list: [{
                        name: '4D SUV',
                        uvc: '123abc'
                    }]
                }]
            }]
        }]
    }]
}

我想将此数组转换为以下内容,其中year,make,model,series和style的每个组合合并为一个哈希并插入到数组中。

 [{:year=> 2016,
  :make=>"Honda",
  :model=>"CRV",
  :series=>"Premium Plus",
  :style=>"4D SUV",
  :uvc=>"123abc"}]

我有一个可行的解决方案,但我想知道是否有人对如何使解决方案更优雅的解决方案有任何想法。

list = []
year_list.each do |y_val|
  vehicle_type = {}
  vehicle_type[:year] = y_val['name']

  make_list = y_val['make_list']
  make_list.each do |k_val|
    vehicle_type[:make] = k_val['name']

    model_list = k_val['model_list']
    model_list.each do |m_val|
      vehicle_type[:model] = m_val['name']

      series_list = m_val['series_list']
      series_list.each do |s_val|
        vehicle_type[:series] = s_val['name']

        style_list = s_val['style_list']
        style_list.each do |st_val|
          vehicle_type[:style] = st_val['name']
          vehicle_type[:uvc] = st_val['uvc']
          list << vehicle_type
        end
      end
    end
  end
end

有没有办法利用Ruby的一些数组方法来做一个更好的解决方案?

编辑:这是一个几乎使用递归工作的解决方案。

VEHICLES = []
ELEMENTS = [:year, :make, :model, :series, :style]

def walk_tree(arr, vehicle={})
  arr[0..1].each do |a|
    name = a['name']

    if a.key?('uvc')
      vehicle[:uvc] = a['uvc']
      VEHICLES << vehicle
      vehicle = {}
      next
    end

    ELEMENTS.each do |s|
      key = s.to_s + '_list'
      if a.key?(key)
        vehicle[s] = name
        walk_tree(a[key], vehicle)
      end
    end

  end
end

walk_tree(year_list)
pp LIST

2 个答案:

答案 0 :(得分:1)

可以在没有任何额外的累加器或临时变量的情况下重写您的解决方案,这将减少代码行的数量并使其清晰。我的解决方案仅使用Array map 方法,该方法将返回所需的结果,但深度包装到数组中。可以使用Array flatten 方法调用删除所有外部数组包装器。 这是irb控制台的输出。

super_hash[:year_list].map do |year|
  year[:make_list].map do |make|
    make[:model_list].map do |model|
      model[:series_list].map do |series|
        series[:style_list].map do |style|
          {
            year: year[:name], 
            make: make[:name], 
            model: model[:name], 
            series: series[:name], 
            style: style[:name], 
            uvc: style[:uvc]
          }
        end
      end
    end
  end
end
#=> [[[[[{:year=>2016, :make=>"Honda", :model=>"CRV", :series=>"Premium Plus", :style=>"4D SUV", :uvc=>"123abc"}]]]]]
[[[[[{:year=>2016, :make=>"Honda", :model=>"CRV", :series=>"Premium Plus", :style=>"4D SUV", :uvc=>"123abc"}]]]]].flatten
#=> [{:year=>2016, :make=>"Honda", :model=>"CRV", :series=>"Premium Plus", :style=>"4D SUV", :uvc=>"123abc"}]

答案 1 :(得分:0)

您可以递归inject,按原样传递所有键值,但要查找_list这样的键值:

l = ->(h,(k,v)){
  if k =~ /(\w+)_list$/
    h[$1] = v.first[:name]
    return v.first.inject(h, &l)
  end
  h[k] = v
  h
}

p year_list.inject({}, &l)