2016-11-17 65 views
1

我有两个哈希数组 - car_model & car_cc如下。对于car_model中的每个散列,我需要查找cc密钥并将其添加到car_model带多个键的Ruby哈希查找

car_model = [ 
    {state: "MH", regno: 5555, model: "alto"}, 
    {state: "MH", regno: 5566, model: "alto"}, 
    {state: "DL", regno: 5555, model: "prius"}, 
    {state: "DL", regno: 5567, model: "nano"} 
] 

car_cc = [ 
    {state: "MH", regno: 5555, cc: 999}, 
    {state: "MH", regno: 5588, cc: 1800}, 
    {state: "DL", regno: 5555, cc: 1119}, 
    {state: "DL", regno: 5567, cc: nil} 
] 

现在我使用的是普通.each回路car_cc查找为cc键,并添加到每个项目中car_model

car_model.each do |cm| 
    car_cc.each do |cc| 
     if(cm["state"]==cc["state"] && cm["regno"]==cc["regno"]) 
      cm["cc"] = cc["cc"] 
      break 
     end 
    end 
end 
预期输出
puts car_model 
{:state=>"MH", :regno=>5555, :model=>"alto", :cc=>999} 
{:state=>"MH", :regno=>5566, :model=>"alto", :cc=>nil} 
{:state=>"DL", :regno=>5555, :model=>"prius", :cc=>1119} 
{:state=>"DL", :regno=>5567, :model=>"nano", :cc=>nil} 
=> nil 
irb(main):008:0> 

是否有这样做的更有效的方式 - 更快,更rubyistic方式?

回答

4

一种方法是car_cc转换成散列便捷键:

cc = car_cc.each_with_object({}) { |car, h| h[car.values_at(:state, :regno)] = car[:cc] } 

,这样就可以执行连接更加容易:

car_model.each { |h| h[:cc] = cc[h.values_at(:state, :regno)] } 

这假定:state /:regno双是在car_cc中是唯一的,并且您要修改car_model。如果你不希望修改car_model,那么你可以说:

car_model_cc = car_model.map { |cm| cm.merge(cc: cc[cm.values_at(:state, :regno)]) } 

复制一切,而加入:cc秒。


当然与数据集这个小小的任何性能差异将太小担心,如果你的数据集大得多,那么你很可能想的东西它都在一个数据库,并让数据库完成沉重的举重。

2
car_model.map do |cm| 
    cm.merge(car_cc.detect do |e| 
      e[:state] == cm[:state] && e[:regno] == cm[:regno] 
      end || {cc: nil}) 
end 

,或者干:

VALS = %i|state regno| 
car_model.map do |cm| 
    cm.merge(car_cc.detect do |e| 
      [e, cm].map { |e| e.values_at(*VALS) }.reduce(:==) 
      end || {cc: nil}) 
end 

如果项目查找的量足够大,我就开始建立一个中间对象:

map = car_cc.group_by { |e| e.values_at(:state, :regno) } 
      .map { |k, v| [k, v.first[:cc]] }.to_h 
#⇒ { 
# [ "MH", 5555 ] => 999, 
# [ "MH", 5588 ] => 1800, 
# [ "DL", 5555 ] => 1119, 
# [ "DL", 5567 ] => nil 
# } 

现在一切都顺利:

car_model.each do |cm| 
    cm[:cc] = map[[cm[:state], cm[:regno]]] 
end 
+0

好主意使用'detect'。 –

1
model = car_model.each_with_object({}) { |g,h| 
    h[g.values_at(:state, :regno)] = g.merge(:cc => nil) } 
    #=> {["MH", 5555]=>{:state=>"MH", :regno=>5555, :model=>"alto", :cc=>nil}, 
    # ["MH", 5566]=>{:state=>"MH", :regno=>5566, :model=>"alto", :cc=>nil}, 
    # ["DL", 5555]=>{:state=>"DL", :regno=>5555, :model=>"prius", :cc=>nil}, 
    # ["DL", 5567]=>{:state=>"DL", :regno=>5567, :model=>"nano", :cc=>nil}} 

cc = car_cc.each_with_object({}) { |g,h| h[g.values_at(:state, :regno)] = g }. 
    select { |k,_| model.key?(k) } 
    #=> {["MH", 5555]=>{:state=>"MH", :regno=>5555, :cc=>999}, 
    # ["DL", 5555]=>{:state=>"DL", :regno=>5555, :cc=>1119}, 
    # ["DL", 5567]=>{:state=>"DL", :regno=>5567, :cc=>nil}} 

(model.merge(cc) { |_,o,n| o.merge(n) }).values 
    #=> [{:state=>"MH", :regno=>5555, :model=>"alto", :cc=>999}, 
    # {:state=>"MH", :regno=>5566, :model=>"alto", :cc=>nil}, 
    # {:state=>"DL", :regno=>5555, :model=>"prius", :cc=>1119}, 
    # {:state=>"DL", :regno=>5567, :model=>"nano", :cc=>nil}] 

cc计算我们除去键 - 值对k,v为其model不包含键k之前首先计算以下散列。

car_cc.each_with_object({}) { |g,h| h[g.values_at(:state, :regno)] = g } 
    #=> {["MH", 5555]=>{:state=>"MH", :regno=>5555, :cc=>999}, 
    # ["MH", 5588]=>{:state=>"MH", :regno=>5588, :cc=>1800}, 
    # ["DL", 5555]=>{:state=>"DL", :regno=>5555, :cc=>1119}, 
    # ["DL", 5567]=>{:state=>"DL", :regno=>5567, :cc=>nil}} 

在最后一行代码中,我们在提取其值之前计算以下散列值。

model.merge(cc) { |_,o,n| o.merge(n) } 
    #=> {["MH", 5555]=>{:state=>"MH", :regno=>5555, :model=>"alto", :cc=>999}, 
    # ["MH", 5566]=>{:state=>"MH", :regno=>5566, :model=>"alto", :cc=>nil}, 
    # ["DL", 5555]=>{:state=>"DL", :regno=>5555, :model=>"prius", :cc=>1119}, 
    # ["DL", 5567]=>{:state=>"DL", :regno=>5567, :model=>"nano", :cc=>nil}} 

这最后一个计算使用的Hash#merge了采用块,以确定存在于被合并两个散列密钥的值的形式。有关三个块变量(这里是_,on,第一个是下划线仅仅是为了表示在块计算中未使用该变量)的解释,请参阅文档。

+0

看过其他答案后,我已经得出结论,我的答案不及@muistooshort给出的答案,并且... –

+0

... @mudasobwa。如果我不是将'cc'合并到'model'中,而是使用'model'的每个键的'find/detect'来查找'cc'的键值对合并成的'select'操作'model',就像Mudsie所做的那样,或者简单地从'cc'添加键':cc'所需的键值对。 –