Created
March 18, 2014 05:04
-
-
Save harssh/9613873 to your computer and use it in GitHub Desktop.
7 daily use cases of Ruby Hash
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 1. How to convert a JSON into a Hash? | |
| You’ve just retrieved a Twitter profile as a JSON: | |
| data = '{ | |
| "name": "Aaron Patterson", | |
| "screen_name": "tenderlove", | |
| "location": "Seattle, WA" | |
| }' | |
| You want to transform it as a Hash for easier data manipulation: | |
| require 'json' | |
| profile = JSON.parse(data) | |
| IRB Output: | |
| => { | |
| "name"=>"Aaron Patterson", | |
| "screen_name"=>"tenderlove", | |
| "location"=>"Seattle, WA" | |
| } | |
| Reference: JSON#parse | |
| 2. How to convert a Hash into a JSON? | |
| In your web application, you track the number of signups per day for the current week: | |
| signups_of_the_week = { | |
| monday: 2, | |
| tuesday: 3, | |
| wednesday: 4, | |
| thursday: 20, | |
| friday: 5, | |
| saturday: 2, | |
| sunday: 5 | |
| } | |
| You can provide them through an API as JSON data: | |
| require 'json' | |
| signups_of_the_week.to_json | |
| IRB Output: | |
| => "{\"monday\":2,\"tuesday\":3,\"wednesday\":4,\"thursday\":20,\"friday\":5,\"saturday\":2,\"sunday\":5}" | |
| Reference: JSON#generate | |
| Side note: JSON#pretty_generate is really helpful for pretty printing and debugging. | |
| 3. How to set default value for a nested Hash? | |
| You have collection of contacts indexed by name, a nested Hash: | |
| contacts = { | |
| 'John' => { | |
| name: 'John', | |
| email: 'john@doe.com' | |
| }, | |
| 'Freddy' => { | |
| name 'Freddy', | |
| email: 'freddy@mercury.com' | |
| } | |
| } | |
| When working with a contact, you don’t want to check every time if it exists or not. You just want to write: | |
| contacts['Jane'][:email] = 'jane@doe.com' | |
| puts contacts['Jane'] | |
| IRB Output: | |
| => {:name=>"Jane", :email=>"jane@doe.com"} | |
| You can do it by setting a complex value when creating the Hash | |
| contacts = Hash.new do |hsh, key| | |
| hsh[key] = { | |
| name: key, | |
| email: '' | |
| } | |
| end | |
| or later with | |
| contacts.default_proc = Proc.new do |hsh, key| | |
| hsh[key] = { | |
| name: key, | |
| email: '' | |
| } | |
| end | |
| References: Hash#new, Hash#default_proc= | |
| 4. How to merge two nested Hashes? | |
| In an online shop, you want to merge a wish list with the current basket, both indexed by product 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 | |
| } | |
| } | |
| With ActiveSupport, you can simply do it with: | |
| require 'active_support/core_ext/hash' # not necessary if in Rails | |
| basket.deep_merge(wish_list) | |
| or without 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 Output: | |
| => { | |
| 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} | |
| } | |
| References: Hash#merge, Hash#deep_merge | |
| 5. How to filter out some keys of a Hash? | |
| You’ve built an histogram of daily sales and stored it in a Hash, the key being the day: | |
| histogram = { | |
| monday: 5, | |
| tuesday: 7, | |
| wednesday: 10, | |
| thursday: 18, | |
| friday: 7, | |
| saturday: 2, | |
| sunday: 0 | |
| } | |
| You want to filter out Saturday and Sunday. With ActiveSupport, you can do it as following | |
| require 'active_support/core_ext/hash' # not necessary if Rails | |
| histogram.except(:saturday, :sunday) | |
| or without ActiveSupport | |
| def filter(hsh, *keys) | |
| hsh.dup.tap do |h| | |
| keys.each { |k| h.delete(k) } | |
| end | |
| end | |
| filter(histogram, :saturday, :sunday) | |
| Another clearer implementation is based on reject (credits to Thiago A.): | |
| def filter2(hsh, *keys) | |
| hsh.reject { |k, _| keys.include? k } | |
| end | |
| Note that if you deal with large collection you should benchmark your implementation to select the best one. | |
| IRB Output: | |
| => {:monday=>5, :tuesday=>7, :wednesday=>10, :thursday=>18, :friday=>7} | |
| Reference: Hash#except, Hash#delete, Hash#reject, Object#dup, Object#tap | |
| 6. How to “sort” a Hash by value? | |
| In a dices game, you keep the score per player in a Hash: | |
| scores = { | |
| 'The Lady' => 3, | |
| 'Fate' => 2, | |
| 'Death' => 10 | |
| } | |
| You want to to sort them by scores. You can do it with: | |
| leaderboard = scores.sort_by { |_, score| -score } | |
| IRB Output: | |
| => [["Death", 10], ["The Lady", 3], ["Fate", 2]] | |
| Reference: Enumerable#sort_by | |
| Side note: Hash enumerates their value in their insertion order. | |
| 7. How to find the differences between two Hashes? | |
| You regularly retrieve data from RSS feeds and put them into a Hash: | |
| entries = { | |
| 1372284000 => "CVE-2013-4073", | |
| 1368482400 => "CVE-2013-2065" | |
| } | |
| When doing an update, you get another Hash: | |
| updated_entries = { | |
| 1385074800 => "CVE-2013-4164", | |
| 1372284000 => "CVE-2013-4073", | |
| 1368482400 => "CVE-2013-2065" | |
| } | |
| You want to spot which entries are new so you can for instance send them by email. You can do it with: | |
| new_entries = updated_entries.dup.delete_if {|k| entries.keys.include? k } | |
| but it’s better and clearer to do with | |
| new_entries = updated_entries.reject { |k, _| entries.include? k } | |
| as you benefit from the fast lookup of Hash (Credits to apeiros) | |
| IRB Output: | |
| => {1385074800=>"CVE-2013-4164"} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment