此文翻譯自7 daily use cases of Ruby Hash,限於本人水平,翻譯不當之處,敬請指教!html
每一天,你都須要跟Hash相處。建立一個新的Hash或者是經過它的某一個鍵去檢索其中的元素這樣的工做,都是常見也是很是簡單的。可是當你須要合併兩個嵌套的Hash或者是從某一個Hash裏邊過濾某些鍵,你可能須要考慮得多一點。經過完整的文檔,你能夠找到對Hash中的每個方法的充分解釋。可是因爲文檔不是面向應用場景的,你可能無法很快找到你的解決方案。在下面,我分享了我平常中常常遇到的Hash中的7個經常使用場景,但願它們對你有用。
web
假設你剛剛接收到一個用JSON表示的Twitter帳號的資料信息:json
data = '{ "name": "Aaron Patterson", "screen_name": "tenderlove", "location": "Seattle, WA" }'
你但願可以將它轉化爲一個Hash,這樣會更方便你進行對數據的操做:api
require 'json' profile = JSON.parse(data)
** 在IRB中的輸出結果:**ruby
=> { "name"=>"Aaron Patterson", "screen_name"=>"tenderlove", "location"=>"Seattle, WA" }
查看文檔:JSON#parseide
在你的web應用程序中,你須要追蹤當前星期每一天新註冊用戶的數量:ui
signups_of_the_week = { monday: 2, tuesday: 3, wednesday: 4, thursday: 20, friday: 5, saturday: 2, sunday: 5 }
你能夠經過API的方式把它們以JSON格式提供給客戶端:翻譯
require 'json' signups_of_the_week.to_json
** 在IRB中的輸出結果:**調試
=> "{\"monday\":2,\"tuesday\":3,\"wednesday\":4,\"thursday\":20,\"friday\":5,\"saturday\":2,\"sunday\":5}"
查看文檔:JSON#generate
邊注:JSON#pretty_generate對於更好的打印以及調試很是有用。code
你有一個以name爲索引的聯繫人的集合,也就是一個嵌套的Hash:
contacts = { 'John' => { name: 'John', email: 'john@doe.com' }, 'Freddy' => { name 'Freddy', email: 'freddy@mercury.com' } }
當你在處理單個聯繫人的時候,你不須要每一次都檢查它是否存在。你只須要寫:
contacts['Jane'][:email] = 'jane@doe.com' puts contacts['Jane']
** IRB輸出 **:
=> {:name=>"Jane", :email=>"jane@doe.com"}
你能夠在建立Hash的時候經過設置代碼塊來實現默認值:
contacts = Hash.new do |hsh, key| hsh[key] = { name: key, email: '' } end
或者是使用:
contacts.default_proc = Proc.new do |hsh, key| hsh[key] = { name: key, email: '' } end
查看文檔:Hash#new, Hash#default_proc
在一個在線商店裏,你想要將一個心願單與當前的購物籃進行合併,這二者都是以商品的id號做爲索引:
wish_list = { 8 => { title: "The Color of Magic", }, 42 => { title: "The Hitch-Hiker's Guide to the Galaxy", price: 5 } } basket = { 8 => { price: 10 }, 1729 => { title: "Ramanujan: Twelve Lectures on Subjects Suggested by His Life and Work", price: 28 } }
藉助於ActiveSupport,你能夠簡單地實現你的目標:
require 'active_support/core_ext/hash' # not necessary if in Rails basket.deep_merge(wish_list)
又或者,在沒有ActiveSupport的狀況下:
def deep_merge(h1, h2) h1.merge(h2) { |key, h1_elem, h2_elem| deep_merge(h1_elem, h2_elem) } end deep_merge(basket, wish_list)
** IRB輸出: **
=> { 8=>{:price=>10, :title=>"The Color of Magic"}, 1729=>{:title=>"Ramanujan: Twelve Lectures on Subjects Suggested by His Life and Work", :price=>28}, 42=>{:title=>"The Hitch-Hiker's Guide to the Galaxy", :price=>5} }
查看文檔:Hash#merge, Hash#deep_merge
你已經建立了一個表示日銷售額的矩形圖,而且你將它以Hash的方式存儲,每一天就是一個key:
histogram = { monday: 5, tuesday: 7, wednesday: 10, thursday: 18, friday: 7, saturday: 2, sunday: 0 }
你想從中過濾掉Saturday以及Sunday。經過ActiveSupport,你能夠像下面這樣作:
require 'active_support/core_ext/hash' # not necessary if Rails histogram.except(:saturday, :sunday)
或者在沒有ActiveSupport的狀況下:
def filter(hsh, *keys) hsh.dup.tap do |h| keys.each { |k| h.delete(k) } end end filter(histogram, :saturday, :sunday)
另外一個簡潔點實現則是基於reject
方法的:
def filter2(hsh, *keys) hsh.reject { |k, _| keys.include? k } end
請注意,若是你正在處理一個比較大的集合,你最好是先衡量下你的實現,一次選擇最好的其中一個實現。
** IRB輸出:**
=> {:monday=>5, :tuesday=>7, :wednesday=>10, :thursday=>18, :friday=>7}
查看文檔:Hash#except, Hash#delete, Hash#reject, Object#dup, Object#tap
在一個骰子類遊戲中,你在Hash中儲存了每個選手的得分:
scores = { 'The Lady' => 3, 'Fate' => 2, 'Death' => 10 }
你想要經過他們的得分對他們進行排序。你能夠這樣作:
leaderboard = scores.sort_by { |_, score| -score }
** IRB輸出:**
=> [["Death", 10], ["The Lady", 3], ["Fate", 2]]
查看文檔:Enumerable#sort_by
邊注:Hash經過元素插入時的順序去枚舉它們的值。
假設你按期地從RSS訂閱源中讀取數據,而且將他們放在了一個Hash裏邊:
entries = { 1372284000 => "CVE-2013-4073", 1368482400 => "CVE-2013-2065" }
當你更新了以後,你可能獲得另外一個Hash:
updated_entries = { 1385074800 => "CVE-2013-4164", 1372284000 => "CVE-2013-4073", 1368482400 => "CVE-2013-2065" }
你想要查找出哪一條記錄纔是新加的,這樣你就能夠經過email的方式將它們發送出去。最好的解決方案是:
new_entries = updated_entries.reject { |k, _| entries.include? k }
** IRB輸出:**
=> {1385074800=>"CVE-2013-4164"}
查看文檔:Hash#include?