我怎么能用Ruby将2个数组和1个哈希变成单个哈希?

时间:2015-08-19 13:20:50

标签: ruby-on-rails arrays ruby hash

我的问题

这里,我有2个数组和1个哈希,

@key_array = %w(year entry amount)

@nums = {
  "sales": [1000, 2000, 3000, 4000],
  "net_income": [20, 30, 50, 60],
}

@years = [2011, 2012, 2013, 2014]

我想做的是将这3个变成这样的

[{"year"=>2011, "entry"=>:sales, "amount"=>1000},
 {"year"=>2012, "entry"=>:sales, "amount"=>2000},
 {"year"=>2013, "entry"=>:sales, "amount"=>3000},
 {"year"=>2014, "entry"=>:sales, "amount"=>4000},
 {"year"=>2011, "entry"=>:net_income, "amount"=>20},
 {"year"=>2012, "entry"=>:net_income, "amount"=>30},
 {"year"=>2013, "entry"=>:net_income, "amount"=>50},
 {"year"=>2014, "entry"=>:net_income, "amount"=>60}]

到目前为止,我已经尝试过这个Ruby代码......

def build_entry_nums_hash
  num_arr = []
  @years.each do |year|
    @nums.each do |key, value|
      value.each do |fin|
        value_array = [year, key, fin]
        hash = {}
        @key_array.zip(value_array).each { |k, v| hash[k] = v }
        num_arr << hash
      end
    end
  end
  num_arr
end

它几乎恢复了我的预期,但有点不对劲。它返回一些不必要的哈希值。

 [{"year"=>2011, "entry"=>:sales, "amount"=>1000},
 {"year"=>2011, "entry"=>:sales, "amount"=>2000},
 {"year"=>2011, "entry"=>:sales, "amount"=>3000},
 {"year"=>2011, "entry"=>:sales, "amount"=>4000},
 ......
 {"year"=>2014, "entry"=>:net_income, "amount"=>20},
 {"year"=>2014, "entry"=>:net_income, "amount"=>30},
 {"year"=>2014, "entry"=>:net_income, "amount"=>50},
 {"year"=>2014, "entry"=>:net_income, "amount"=>60}]

你能给我一些建议吗?

现状

我不确定这是否有必要,所以如果你担心我为什么必须将这些数组和哈希转换成一个哈希,请仔细阅读。

我正在尝试使用Nokogiri从网站解析一些财务数据。数据以HTML表格标签编写,看起来像Excel电子表格。我的目标是使用我的rails显示这些数据。目前,我能够得到数字并且在努力将我如何将它们放入rails DB中。如果我能做的话,这很好......

Findata.create{"year"=>2011, "entry"=>:sales, "amount"=>1000} 

正确地获得财务数据非常容易,我做了像@num这样的hahs。我需要的是混合其他2个数组并得到我需要的哈希值。

编辑:我已使用哈希

更正了数组中的错误

2 个答案:

答案 0 :(得分:0)

arr = []
@nums.each do |num_key, num_arr|
  @years.each_with_index do |year,i|
    arr << {"year" => year, "entry" => num_key.to_sym, "amount" => num_arr[i]}
  end
end;arr

给我

[{"amount"=>20, "entry"=>:net_income, "year"=>2011},
{"amount"=>30, "entry"=>:net_income, "year"=>2012},
{"amount"=>50, "entry"=>:net_income, "year"=>2013},
{"amount"=>60, "entry"=>:net_income, "year"=>2014},
{"amount"=>1000, "entry"=>:sales, "year"=>2011},
{"amount"=>2000, "entry"=>:sales, "year"=>2012},
{"amount"=>3000, "entry"=>:sales, "year"=>2013},
{"amount"=>4000, "entry"=>:sales, "year"=>2014}]
编辑:put&#34 ;; arr&#34;在循环之后,你留下了保存哈希值的arr变量。

答案 1 :(得分:0)

我重构了Max的答案。

  def build_hash
    @nums.flat_map do |num_key, num_arr|
      @years.map.with_index do |year, i|
        {"year" => year, "entry" => num_key.to_sym, "amount" => num_arr[i]}
      end
    end
  end

仅供参考,这是代码和规范。

require 'spec_helper'

describe 'Array to Hash' do
  before do
    @key_array = %w(year entry amount)

    @nums = {
        "sales": [1000, 2000, 3000, 4000],
        "net_income": [20, 30, 50, 60],
    }

    @years = [2011, 2012, 2013, 2014]
  end

  let(:expected) do
    [{"year"=>2011, "entry"=>:sales, "amount"=>1000},
     {"year"=>2012, "entry"=>:sales, "amount"=>2000},
     {"year"=>2013, "entry"=>:sales, "amount"=>3000},
     {"year"=>2014, "entry"=>:sales, "amount"=>4000},
     {"year"=>2011, "entry"=>:net_income, "amount"=>20},
     {"year"=>2012, "entry"=>:net_income, "amount"=>30},
     {"year"=>2013, "entry"=>:net_income, "amount"=>50},
     {"year"=>2014, "entry"=>:net_income, "amount"=>60}]
  end

  def build_hash
    @nums.flat_map do |num_key, num_arr|
      @years.map.with_index do |year, i|
        {"year" => year, "entry" => num_key.to_sym, "amount" => num_arr[i]}
      end
    end
  end

  specify do
    expect(build_hash).to eq expected
  end
end