2016-11-17 66 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'所需的鍵值對。 –