此文翻译自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?