SlideShare uma empresa Scribd logo
1 de 24
Ruby Arrays & Hashes
   with Examples
Arrays & Hashes

 Like all high-level languages, Ruby has built-in support for arrays, objects that
  contain ordered lists of other objects.

 Each element is a reference to some object
 The object references can be -
      predefined variables
      anonymous objects created on the spot ('my string', 4.7, or
       MyClass.new)
      expressions (a+b, object.method).
 You can use arrays (often in conjunction with hashes) to build and use
  complex data structures without having to define any custom classes.

 Hash is a collection data structure consisting of key-value pairs. Key and value can be any
    object.
a1 = []                             # => []
a2 = [1, 2, 3]                     # => [1, 2, 3]
a3 = [1, 2, 3, 'a', 'b', 'c', nil] # => [1, 2, 3, "a", "b", "c", nil]
n1 = 4
n2 = 6
sum_and_difference = [n1, n2, n1+n2, n1-n2]              # => [4, 6, 10, -2]

%w{1 2 3}                            # => ["1", "2", "3"]
%w{The rat sat on the mat}           # => ["The", "rat", "sat", "on", "the", "mat"]

a = [1, 2, 3]       # => [1, 2, 3]
a << 4.0            # => [1, 2, 3, 4.0]
a << 'five‘         # => [1, 2, 3, 4.0, "five"]

a = [1,2,3]         # => [1, 2, 3]
a << [4, 5, 6]      # => [1, 2, 3, [4, 5, 6]]
a << a              # => [1, 2, 3, [4, 5, 6], […]]
a = [1, 2, 3, [4, 5, 6]]
a.size                     # => 4
a << a                     # => [1, 2, 3, [4, 5, 6], […]]
a.size                     # => 5

a[0]                       # => 1
a[3]                       # => [4, 5, 6]
a[3][0]                    # => 4
a[3].size                  # => 3

a[-2]                      # => [4, 5, 6]
a[-1]                      # => [1, 2, 3, [4, 5, 6], […]]
a[a.size-1]                # => [1, 2, 3, [4, 5, 6], […]]

a[-1][-1]                  # => [1, 2, 3, [4, 5, 6], […]]
a[-1][-1][-1]              # => [1, 2, 3, [4, 5, 6], […]]
Iterating over an array
 Iterate over the array with Enumerable#each. Put into a block the code you
 want to execute for each item in the array.

    [1, 2, 3, 4].each { |x| puts x }

 If you want to produce a new array based on a transformation of some other array, use
  Enumerable#collect along with a block that takes one element and transforms it

            [1, 2, 3, 4].collect { |x| x ** 2 } # => [1, 4, 9, 16]

 If you need to have the array indexes along with the array elements, use
  Enumerable#each_with_index.

               ['a', 'b', 'c'].each_with_index do |item, index|
                            puts "At position #{index}: #{item}“
               end

 To iterate over a list in reverse order, use the reverse_each method

            [1, 2, 3, 4]. reverse_each { |x| puts x }
Continued …
 Enumerable#collect has a destructive equivalent: Array# collect!, also known as Array#map!
 It replaces each item in the old array with the corresponding value from the code block.
 This saves memory and time, but it destroys the old array

array = ['a', 'b', 'c']
array.collect! { |x| x.upcase }
array                         # => ["A", "B", "C"]

array.map! { |x| x.downcase }
array # => ["a", "b", "c"]

 If you need to skip certain elements of an array, you can use the iterator methods
  Range#step and Integer#upto instead of Array#each


     3.upto(array.length-1) { |i| puts "Value #{array[i]}" }

  (0..array.length-1).step(2) do |i|
              puts "Letter #{array[i]} is #{array[i+1]}"
  end
Continued…

 To add an array of key-value pairs to a hash, either iterate over the array with Array#each, or
  pass the hash into Array#inject.
 Using inject is slower but the code is more concise.



squares = [[1,1], [2,4], [3,9]]

results = {}
squares.each { |k,v| results[k] = v }
results      # => {1=>1, 2=>4, 3=>9}

squares.inject({}) { |h, kv| h[kv[0]] = kv[1]; h }
# => {1=>1, 2=>4, 3=>9}
Continued…

 To turn a flat array into the key-value pairs of a hash, iterate over the array elements two at a
  time

class Array
 def into_hash(h)
      unless size % 2 == 0
        raise StandardError, "Expected array with even number of elements“
      end
      0.step(size-1, 2) { |x| h[self[x]] = self[x+1] }
      h
  end
 end

squares = [1,1,2,3,4,9]
results = {}
squares.into_hash(results) # => {1=>1, 2=>3, 4=>9}

[1,1,2].into_hash(results) # StandardError: Expected array with even number of elements
Continued…

 To insert into a hash every key-value from another hash, use Hash#merge!.
 If a key is present in both hashes when a.merge!(b) is called, the value in b takes precedence
  over the value in a.

squares = { 1 => 1, 2 => 4, 3 => 9}
cubes = { 3 => 27, 4 => 256, 5 => 3125}

squares.merge!(cubes)
squares          # =>{5=>3125, 1=>1, 2=>4, 3=>27, 4=>256}
cubes           # =>{5=>3125, 3=>27, 4=>256}


 Hash#merge! also has a nondestructive version, Hash#merge, which creates a new Hash with
  elements from both parent hashes.
 Again, the hash passed in as an argument takes precedence.
 To completely replace the entire contents of one hash with the contents of another, use
  Hash#replace.

squares = { 1 => 1, 2 => 4, 3 => 9}
cubes = { 1 => 1, 2 => 8, 3 => 27}
squares.replace(cubes)
squares      # => {1=>1, 2=>8, 3=>27}

 This is different from simply assigning the cubes hash to the squares variable name, because
  cubes and squares are still separate hashes.
 They just happen to contain the same elements in the above example.
 Changing cubes won't affect squares.

cubes[4] = 64
squares     # => {1=>1, 2=>8, 3=>27}

 Hash#replace is useful for reverting a Hash to known default values.
Removing elements from a Hash
 To remove specific element from hash, pass the key into Hash#delete
h = {}
h[1] = 10
h             # => {1=>10}
h.delete(1)
h             # => {}

 Don't try to delete an element from a hash by mapping it to nil.
 It's true that, by default, you get nil when you look up a key that's not in the hash, but there's
  a difference between a key that's missing from the hash and a key that's present but mapped
  to nil.
 Hash#has_key? will see a key mapped to nil, as will Hash#each and all other methods except
  for a simple fetch.

h = {}
h[5]           # => nil
h[5] = 10
h[5]           # => 10
h[5] = nil
h[5]           # => nil
h.keys         # => [5]
h.delete(5)
h.keys         # => []
Example
 Use the Hash#delete_if iterator to delete key-value pairs for which a certain code block returns true
 Hash#reject works the same way, but it works on a copy of the Hash
class Hash
 def delete_value(value)
  delete_if { |k,v| v == value }
 end
end
h = {'apple' => 'green', 'potato' => 'red', 'sun' => 'yellow', 'katydid' => 'green' }
h.delete_value('green')
h                   # => {"sun"=>"yellow", "potato"=>"red"}

   The below code implements the opposite of Hash#merge; it extracts one hash from another
class Hash
 def remove_hash(other_hash)
  delete_if { |k,v| other_hash[k] == v }
 end
end
squares = { 1 => 1, 2 => 4, 3 => 9 }
doubles = { 1 => 2, 2 => 4, 3 => 6 }
squares.remove_hash(doubles)
squares              # => {1=>1, 3=>9}

   To wipe out the entire contents of a Hash, use Hash#clear
Using an array or other modifiable object as hash key

 A naive solution tends to lose hash values once the keys are modified


coordinates = [10, 5]
treasure_map = { coordinates => 'jewels' }
treasure_map[coordinates]            # => "jewels“


# Add a z-coordinate to indicate how deep the treasure is buried.
coordinates << -5
coordinates                          # => [10, 5, -5]
treasure_map[coordinates]            # => nil


 The easiest solution is to call the Hash#rehash method every time you modify one of the

    hash's keys
treasure_map.rehash
treasure_map[coordinates]            # => "jewels"
Continued…

module ReliablyHashable
 def hash
  return object_id
 end
end

class ReliablyHashableArray < Array
 include ReliablyHashable
end

coordinates = ReliablyHashableArray.new([10,5])
treasure_map = { coordinates => 'jewels' }
treasure_map[coordinates]       # => "jewels“

# Add a z-coordinate to indicate how deep the treasure is buried.
coordinates.push(-5)
treasure_map[coordinates]        # => "jewels"
Continued…
 The implementation of hash given in the previous solution violates the principle that
  different representations of the same data should have the same hash code.
 This means that two ReliablyHashableArray objects will have different hash codes even if
  they have the same contents

a = [1,2]
b = a.clone
a.hash                  # => 11
b.hash                  # => 11



a = ReliablyHashableArray.new([1,2])
b = a.clone
a.hash                   # => -606031406
b.hash                   # => -606034266


 The solution is to freeze your hash keys.
 Any frozen object can be reliably used as a hash key, since you can't do anything to a frozen
  object that would cause its hash code to change
Keeping multiple values for the same hash key
hash = Hash.new { |hash, key| hash[key] = [] }
raw_data = [ [1, 'a'], [1, 'b'], [1, 'c'], [2, 'a'], [2, ['b', 'c']], [3, 'c'] ]
raw_data.each { |x,y| hash[x] << y }
hash      # => {1=>["a", "b", "c"], 2=>["a", ["b", "c"]], 3=>["c"]}


 It's possible to subclass Hash to act like a normal hash until a key collision occurs, and then
  start keeping an array of values for the key that suffered the collision

class MultiValuedHash < Hash
 def []=(key, value)
  if has_key?(key)
       super(key, [value, self[key]].flatten)
  else
    super
  end
  end
end

hash = MultiValuedHash.new
raw_data.each { |x,y| hash[x] = y }
hash          # => {1=>["c", "b", "a"], 2=>["b", "c", "a"], 3=>"c"}
Iterating over a hash
 Note that each and each_pair return the key-value pairs in an apparently random order
hash = { 1 => 'one', [1,2] => 'two', 'three' => 'three' }
hash.each_pair { |key, value| puts "#{key.inspect} maps to #{value}"}
# [1, 2] maps to two
# "three" maps to three
# 1 maps to one


 Use Hash#each_key if you only need the keys of a hash
active_toggles = { 'super' => true, 'meta' => true, 'hyper' => true }
active_toggles.each_key { |active| puts active }

# hyper # meta # super



 Use Hash#each_value if you only need the values of a hash
favorite_colors = { 'Alice' => :red, 'Bob' => :violet, 'Mallory' => :blue, 'Carol' => :blue, 'Dave' => :violet }
summary = Hash.new(0)
favorite_colors.each_value { |x| summary[x] += 1 }
summary # => {:red=>1, :violet=>2, :blue=>2}
Continued…
 Don't modify the keyset of a hash during an iteration, or you'll get undefined results and
  possibly a RuntimeError
1.upto(100) { |x| hash[x] = true }
hash.keys { |k| hash[k * 2] = true }
# RuntimeError: hash modified during iteration


 Using an array as intermediary
hash = {1 => 2, 2 => 2, 3 => 10}
hash.keys                      # => [1, 2, 3]
hash.values                    # => [2, 2, 10]
hash.to_a                      # => [[1, 2], [2, 2], [3, 10]]


 Sorting the result of Hash#keys.
extensions = { 'Alice' => '104', 'Carol' => '210', 'Bob' => '110' }
extensions.keys.sort.each do |k|
  puts "#{k} can be reached at extension ##{extensions[k]}“
end
# Alice can be reached at extension #104
# Bob can be reached at extension #110
# Carol can be reached at extension #210
Continued…
 Hash#sort and Hash#sort_by turn a hash into an array of two-element subarrays (one for
  each key-value pair), then sort the array of arrays however you like
 This code sorts a to-do list by priority, then alphabetically
to_do = { 'Clean car' => 5, 'Take kangaroo to vet' => 3, 'Realign plasma conduit' => 3 }
to_do.sort_by { |task, priority| [priority, task] }.each { |k,v| puts k }

# Realign plasma conduit
# Take kangaroo to vet
# Clean car

 This code sorts a hash full of number pairs according to the magnitude of the difference
  between the key and the value
transform_results = { 4 => 8, 9 => 9, 10 => 6, 2 => 7, 6 => 5 }
by_size_of_difference = transform_results.sort_by { |x, y| (x-y).abs }
by_size_of_difference.each { |x, y| puts "f(#{x})=#{y}: difference #{y-x}" }

# f(9)=9: difference 0
# f(6)=5: difference -1
# f(10)=6: difference -4
# f(4)=8: difference 4
# f(2)=7: difference 5
Iterating over a hash in insertion order
 To iterate over a hash in the order in which the elements were added to the hash.
 Use the orderedhash library
require 'orderedhash‘
h = OrderedHash.new
h[1] = 1
h["second"] = 2
h[:third] = 3
h.keys                         # => [1, "second", :third]
h.values                       # => [1, 2, 3]
h.each { |k,v| puts "The #{k} counting number is #{v}" }
# The 1 counting number is 1 # The second counting number is 2   # The third counting number is 3

 OrderedHash is a subclass of Hash that keeps an array of the keys in insertion order.
 When you add key-value pair to the hash, OrderedHash modifies both the underlying hash
  and the array
 But any operation that modifies an OrderedHash may also modify the internal array, so it's
  slower than just using a hash.
 OrderedHash#delete is especially slow, since it must perform a linear search of the internal
  array to find the key being deleted.
 Hash#delete runs in constant time, but OrderedHash#delete takes time proportionate to size
  of the hash.
Inverting a hash

    To switch the keys and values of hash

phone_directory = { 'Alice' => '555-1212', 'Bob' => '555-1313', 'Mallory' => '111-1111' }
phone_directory.invert
# => {"111-1111"=>"Mallory", "555-1212"=>"Alice", "555-1313"=>"Bob"}



    Hash#invert probably won't do what you want if your hash maps more than one key to the same
     value.
    Only one of the keys for that value will show up as a value in the inverted hash

phone_directory = { 'Alice' => '555-1212', 'Bob' => '555-1313', 'Carol' => '555-1313', 'Mallory' => '111-1111', 'Ted' =>
     '555-1212' }
phone_directory.invert
# => {"111-1111"=>"Mallory", "555-1212"=>"Ted", "555-1313"=>"Bob"}



    To preserve all the data from the original hash, write a version of invert that keeps an array of
     values for each key …
Safe invert
class Hash
 def safe_invert
   new_hash = {}
   self.each do |k,v|
     if v.is_a? Array
       v.each { |x| new_hash.add_or_append(x, k) }
     else
       new_hash.add_or_append(v, k)
     end
   end
   return new_hash
 end
 def add_or_append(key, value)
   if has_key?(key)
          self[key] = [value, self[key]].flatten
   else
     self[key] = value
   end
  end
end

phone_directory.safe_invert               # => {"111-1111"=>"Mallory", "555-1212"=>["Ted", "Alice"], "555-1313"=>["Bob", "Carol"]}
phone_directory.safe_invert.safe_invert    # => {"Alice"=>"555-1212", "Mallory"=>"111-1111", "Ted"=>"555-1212", "Carol"=>"555-1313",
     "Bob"=>"555-1313"}
Continued…

 Ideally, if you called an inversion method twice you'd always get the same data you started
  with.

 The safe_invert method does better than invert on this score, but it's not perfect.

 If your original hash used arrays as hash keys, safe_invert will act as if you'd individually
  mapped each element in the array to the same value.

 Call safe_invert twice, and the arrays will be gone.
Thank you !

Mais conteúdo relacionado

Mais procurados

An Introduction To NoSQL & MongoDB
An Introduction To NoSQL & MongoDBAn Introduction To NoSQL & MongoDB
An Introduction To NoSQL & MongoDBLee Theobald
 
(Fast) Introduction to HTML & CSS
(Fast) Introduction to HTML & CSS (Fast) Introduction to HTML & CSS
(Fast) Introduction to HTML & CSS Dave Kelly
 
Working With a Real-World Dataset in Neo4j: Import and Modeling
Working With a Real-World Dataset in Neo4j: Import and ModelingWorking With a Real-World Dataset in Neo4j: Import and Modeling
Working With a Real-World Dataset in Neo4j: Import and ModelingNeo4j
 
Seminar Presentation Hadoop
Seminar Presentation HadoopSeminar Presentation Hadoop
Seminar Presentation HadoopVarun Narang
 
Retail referencearchitecture productcatalog
Retail referencearchitecture productcatalogRetail referencearchitecture productcatalog
Retail referencearchitecture productcatalogMongoDB
 
Web front end development introduction to html css and javascript
Web front end development introduction to html css and javascriptWeb front end development introduction to html css and javascript
Web front end development introduction to html css and javascriptMarc Huang
 
SSR with Quasar Framework - JSNation 2019
SSR with Quasar Framework - JSNation 2019SSR with Quasar Framework - JSNation 2019
SSR with Quasar Framework - JSNation 2019Razvan Stoenescu
 
02 JavaScript Syntax
02 JavaScript Syntax02 JavaScript Syntax
02 JavaScript SyntaxYnon Perek
 
An introduction to MongoDB
An introduction to MongoDBAn introduction to MongoDB
An introduction to MongoDBCésar Trigo
 
Leveraging Neo4j With Apache Spark
Leveraging Neo4j With Apache SparkLeveraging Neo4j With Apache Spark
Leveraging Neo4j With Apache SparkNeo4j
 
Background property in css
Background property in cssBackground property in css
Background property in cssDhruvin Nakrani
 
Transparent Encryption in HDFS
Transparent Encryption in HDFSTransparent Encryption in HDFS
Transparent Encryption in HDFSDataWorks Summit
 
Efficient, maintainable CSS
Efficient, maintainable CSSEfficient, maintainable CSS
Efficient, maintainable CSSRuss Weakley
 
Intro To MongoDB
Intro To MongoDBIntro To MongoDB
Intro To MongoDBAlex Sharp
 

Mais procurados (20)

Key-Value NoSQL Database
Key-Value NoSQL DatabaseKey-Value NoSQL Database
Key-Value NoSQL Database
 
Mongodb
MongodbMongodb
Mongodb
 
An Introduction To NoSQL & MongoDB
An Introduction To NoSQL & MongoDBAn Introduction To NoSQL & MongoDB
An Introduction To NoSQL & MongoDB
 
(Fast) Introduction to HTML & CSS
(Fast) Introduction to HTML & CSS (Fast) Introduction to HTML & CSS
(Fast) Introduction to HTML & CSS
 
Working With a Real-World Dataset in Neo4j: Import and Modeling
Working With a Real-World Dataset in Neo4j: Import and ModelingWorking With a Real-World Dataset in Neo4j: Import and Modeling
Working With a Real-World Dataset in Neo4j: Import and Modeling
 
Seminar Presentation Hadoop
Seminar Presentation HadoopSeminar Presentation Hadoop
Seminar Presentation Hadoop
 
Big Data Analytics Part2
Big Data Analytics Part2Big Data Analytics Part2
Big Data Analytics Part2
 
Retail referencearchitecture productcatalog
Retail referencearchitecture productcatalogRetail referencearchitecture productcatalog
Retail referencearchitecture productcatalog
 
Web front end development introduction to html css and javascript
Web front end development introduction to html css and javascriptWeb front end development introduction to html css and javascript
Web front end development introduction to html css and javascript
 
An introduction to MongoDB
An introduction to MongoDBAn introduction to MongoDB
An introduction to MongoDB
 
SSR with Quasar Framework - JSNation 2019
SSR with Quasar Framework - JSNation 2019SSR with Quasar Framework - JSNation 2019
SSR with Quasar Framework - JSNation 2019
 
02 JavaScript Syntax
02 JavaScript Syntax02 JavaScript Syntax
02 JavaScript Syntax
 
An introduction to MongoDB
An introduction to MongoDBAn introduction to MongoDB
An introduction to MongoDB
 
Leveraging Neo4j With Apache Spark
Leveraging Neo4j With Apache SparkLeveraging Neo4j With Apache Spark
Leveraging Neo4j With Apache Spark
 
Background property in css
Background property in cssBackground property in css
Background property in css
 
Transparent Encryption in HDFS
Transparent Encryption in HDFSTransparent Encryption in HDFS
Transparent Encryption in HDFS
 
CSS Grid
CSS GridCSS Grid
CSS Grid
 
Efficient, maintainable CSS
Efficient, maintainable CSSEfficient, maintainable CSS
Efficient, maintainable CSS
 
Intro To MongoDB
Intro To MongoDBIntro To MongoDB
Intro To MongoDB
 
MongoDB
MongoDBMongoDB
MongoDB
 

Destaque

Introduction to ruby eval
Introduction to ruby evalIntroduction to ruby eval
Introduction to ruby evalNiranjan Sarade
 
Ruby Language: Array, Hash and Iterators
Ruby Language: Array, Hash and IteratorsRuby Language: Array, Hash and Iterators
Ruby Language: Array, Hash and IteratorsSarah Allen
 
Constructors, Intro to Ruby Classes Part II
Constructors, Intro to Ruby Classes Part IIConstructors, Intro to Ruby Classes Part II
Constructors, Intro to Ruby Classes Part IIJuan Leal
 
Sorting techniques in Perl
Sorting techniques in PerlSorting techniques in Perl
Sorting techniques in PerlYogesh Sawant
 
(BDT303) Construct Your ETL Pipeline with AWS Data Pipeline, Amazon EMR, and ...
(BDT303) Construct Your ETL Pipeline with AWS Data Pipeline, Amazon EMR, and ...(BDT303) Construct Your ETL Pipeline with AWS Data Pipeline, Amazon EMR, and ...
(BDT303) Construct Your ETL Pipeline with AWS Data Pipeline, Amazon EMR, and ...Amazon Web Services
 

Destaque (6)

Introduction to ruby eval
Introduction to ruby evalIntroduction to ruby eval
Introduction to ruby eval
 
16 ruby hashes
16 ruby hashes16 ruby hashes
16 ruby hashes
 
Ruby Language: Array, Hash and Iterators
Ruby Language: Array, Hash and IteratorsRuby Language: Array, Hash and Iterators
Ruby Language: Array, Hash and Iterators
 
Constructors, Intro to Ruby Classes Part II
Constructors, Intro to Ruby Classes Part IIConstructors, Intro to Ruby Classes Part II
Constructors, Intro to Ruby Classes Part II
 
Sorting techniques in Perl
Sorting techniques in PerlSorting techniques in Perl
Sorting techniques in Perl
 
(BDT303) Construct Your ETL Pipeline with AWS Data Pipeline, Amazon EMR, and ...
(BDT303) Construct Your ETL Pipeline with AWS Data Pipeline, Amazon EMR, and ...(BDT303) Construct Your ETL Pipeline with AWS Data Pipeline, Amazon EMR, and ...
(BDT303) Construct Your ETL Pipeline with AWS Data Pipeline, Amazon EMR, and ...
 

Semelhante a Ruby's Arrays and Hashes with examples

Ruby初級者向けレッスン 48回 ─── Array と Hash
Ruby初級者向けレッスン 48回 ─── Array と HashRuby初級者向けレッスン 48回 ─── Array と Hash
Ruby初級者向けレッスン 48回 ─── Array と Hashhigaki
 
Let’s Talk About Ruby
Let’s Talk About RubyLet’s Talk About Ruby
Let’s Talk About RubyIan Bishop
 
Lecture14_15_Hashing.pptx
Lecture14_15_Hashing.pptxLecture14_15_Hashing.pptx
Lecture14_15_Hashing.pptxSLekshmiNair
 
Useful javascript
Useful javascriptUseful javascript
Useful javascriptLei Kang
 
DS Unit 1.pptx
DS Unit 1.pptxDS Unit 1.pptx
DS Unit 1.pptxchin463670
 
Adventures in Optimization
Adventures in OptimizationAdventures in Optimization
Adventures in OptimizationDavid Golden
 
A quick introduction to R
A quick introduction to RA quick introduction to R
A quick introduction to RAngshuman Saha
 
18 hashing
18 hashing18 hashing
18 hashingdeonnash
 
A limited guide to intermediate and advanced Ruby
A limited guide to intermediate and advanced RubyA limited guide to intermediate and advanced Ruby
A limited guide to intermediate and advanced RubyVysakh Sreenivasan
 
Underscore.js
Underscore.jsUnderscore.js
Underscore.jstimourian
 
[1062BPY12001] Data analysis with R / week 2
[1062BPY12001] Data analysis with R / week 2[1062BPY12001] Data analysis with R / week 2
[1062BPY12001] Data analysis with R / week 2Kevin Chun-Hsien Hsu
 
Python Variable Types, List, Tuple, Dictionary
Python Variable Types, List, Tuple, DictionaryPython Variable Types, List, Tuple, Dictionary
Python Variable Types, List, Tuple, DictionarySoba Arjun
 

Semelhante a Ruby's Arrays and Hashes with examples (20)

Ruby初級者向けレッスン 48回 ─── Array と Hash
Ruby初級者向けレッスン 48回 ─── Array と HashRuby初級者向けレッスン 48回 ─── Array と Hash
Ruby初級者向けレッスン 48回 ─── Array と Hash
 
Let’s Talk About Ruby
Let’s Talk About RubyLet’s Talk About Ruby
Let’s Talk About Ruby
 
14078956.ppt
14078956.ppt14078956.ppt
14078956.ppt
 
Lecture14_15_Hashing.pptx
Lecture14_15_Hashing.pptxLecture14_15_Hashing.pptx
Lecture14_15_Hashing.pptx
 
Useful javascript
Useful javascriptUseful javascript
Useful javascript
 
Potential Friend Finder
Potential Friend FinderPotential Friend Finder
Potential Friend Finder
 
DS Unit 1.pptx
DS Unit 1.pptxDS Unit 1.pptx
DS Unit 1.pptx
 
Adventures in Optimization
Adventures in OptimizationAdventures in Optimization
Adventures in Optimization
 
Plc (1)
Plc (1)Plc (1)
Plc (1)
 
A quick introduction to R
A quick introduction to RA quick introduction to R
A quick introduction to R
 
Recursion Lecture in C++
Recursion Lecture in C++Recursion Lecture in C++
Recursion Lecture in C++
 
Intoduction to php arrays
Intoduction to php arraysIntoduction to php arrays
Intoduction to php arrays
 
P3 2018 python_regexes
P3 2018 python_regexesP3 2018 python_regexes
P3 2018 python_regexes
 
Recursion Lecture in Java
Recursion Lecture in JavaRecursion Lecture in Java
Recursion Lecture in Java
 
18 hashing
18 hashing18 hashing
18 hashing
 
A limited guide to intermediate and advanced Ruby
A limited guide to intermediate and advanced RubyA limited guide to intermediate and advanced Ruby
A limited guide to intermediate and advanced Ruby
 
Python lecture 05
Python lecture 05Python lecture 05
Python lecture 05
 
Underscore.js
Underscore.jsUnderscore.js
Underscore.js
 
[1062BPY12001] Data analysis with R / week 2
[1062BPY12001] Data analysis with R / week 2[1062BPY12001] Data analysis with R / week 2
[1062BPY12001] Data analysis with R / week 2
 
Python Variable Types, List, Tuple, Dictionary
Python Variable Types, List, Tuple, DictionaryPython Variable Types, List, Tuple, Dictionary
Python Variable Types, List, Tuple, Dictionary
 

Último

WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfSeasiaInfotech2
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesZilliz
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 

Último (20)

WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdf
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector Databases
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 

Ruby's Arrays and Hashes with examples

  • 1. Ruby Arrays & Hashes with Examples
  • 2. Arrays & Hashes  Like all high-level languages, Ruby has built-in support for arrays, objects that contain ordered lists of other objects.  Each element is a reference to some object  The object references can be -  predefined variables  anonymous objects created on the spot ('my string', 4.7, or MyClass.new)  expressions (a+b, object.method).  You can use arrays (often in conjunction with hashes) to build and use complex data structures without having to define any custom classes.  Hash is a collection data structure consisting of key-value pairs. Key and value can be any object.
  • 3. a1 = [] # => [] a2 = [1, 2, 3] # => [1, 2, 3] a3 = [1, 2, 3, 'a', 'b', 'c', nil] # => [1, 2, 3, "a", "b", "c", nil] n1 = 4 n2 = 6 sum_and_difference = [n1, n2, n1+n2, n1-n2] # => [4, 6, 10, -2] %w{1 2 3} # => ["1", "2", "3"] %w{The rat sat on the mat} # => ["The", "rat", "sat", "on", "the", "mat"] a = [1, 2, 3] # => [1, 2, 3] a << 4.0 # => [1, 2, 3, 4.0] a << 'five‘ # => [1, 2, 3, 4.0, "five"] a = [1,2,3] # => [1, 2, 3] a << [4, 5, 6] # => [1, 2, 3, [4, 5, 6]] a << a # => [1, 2, 3, [4, 5, 6], […]]
  • 4. a = [1, 2, 3, [4, 5, 6]] a.size # => 4 a << a # => [1, 2, 3, [4, 5, 6], […]] a.size # => 5 a[0] # => 1 a[3] # => [4, 5, 6] a[3][0] # => 4 a[3].size # => 3 a[-2] # => [4, 5, 6] a[-1] # => [1, 2, 3, [4, 5, 6], […]] a[a.size-1] # => [1, 2, 3, [4, 5, 6], […]] a[-1][-1] # => [1, 2, 3, [4, 5, 6], […]] a[-1][-1][-1] # => [1, 2, 3, [4, 5, 6], […]]
  • 5. Iterating over an array  Iterate over the array with Enumerable#each. Put into a block the code you want to execute for each item in the array. [1, 2, 3, 4].each { |x| puts x }  If you want to produce a new array based on a transformation of some other array, use Enumerable#collect along with a block that takes one element and transforms it [1, 2, 3, 4].collect { |x| x ** 2 } # => [1, 4, 9, 16]  If you need to have the array indexes along with the array elements, use Enumerable#each_with_index. ['a', 'b', 'c'].each_with_index do |item, index| puts "At position #{index}: #{item}“ end  To iterate over a list in reverse order, use the reverse_each method [1, 2, 3, 4]. reverse_each { |x| puts x }
  • 6. Continued …  Enumerable#collect has a destructive equivalent: Array# collect!, also known as Array#map!  It replaces each item in the old array with the corresponding value from the code block.  This saves memory and time, but it destroys the old array array = ['a', 'b', 'c'] array.collect! { |x| x.upcase } array # => ["A", "B", "C"] array.map! { |x| x.downcase } array # => ["a", "b", "c"]  If you need to skip certain elements of an array, you can use the iterator methods Range#step and Integer#upto instead of Array#each 3.upto(array.length-1) { |i| puts "Value #{array[i]}" } (0..array.length-1).step(2) do |i| puts "Letter #{array[i]} is #{array[i+1]}" end
  • 7. Continued…  To add an array of key-value pairs to a hash, either iterate over the array with Array#each, or pass the hash into Array#inject.  Using inject is slower but the code is more concise. squares = [[1,1], [2,4], [3,9]] results = {} squares.each { |k,v| results[k] = v } results # => {1=>1, 2=>4, 3=>9} squares.inject({}) { |h, kv| h[kv[0]] = kv[1]; h } # => {1=>1, 2=>4, 3=>9}
  • 8. Continued…  To turn a flat array into the key-value pairs of a hash, iterate over the array elements two at a time class Array def into_hash(h) unless size % 2 == 0 raise StandardError, "Expected array with even number of elements“ end 0.step(size-1, 2) { |x| h[self[x]] = self[x+1] } h end end squares = [1,1,2,3,4,9] results = {} squares.into_hash(results) # => {1=>1, 2=>3, 4=>9} [1,1,2].into_hash(results) # StandardError: Expected array with even number of elements
  • 9. Continued…  To insert into a hash every key-value from another hash, use Hash#merge!.  If a key is present in both hashes when a.merge!(b) is called, the value in b takes precedence over the value in a. squares = { 1 => 1, 2 => 4, 3 => 9} cubes = { 3 => 27, 4 => 256, 5 => 3125} squares.merge!(cubes) squares # =>{5=>3125, 1=>1, 2=>4, 3=>27, 4=>256} cubes # =>{5=>3125, 3=>27, 4=>256}  Hash#merge! also has a nondestructive version, Hash#merge, which creates a new Hash with elements from both parent hashes.  Again, the hash passed in as an argument takes precedence.
  • 10.  To completely replace the entire contents of one hash with the contents of another, use Hash#replace. squares = { 1 => 1, 2 => 4, 3 => 9} cubes = { 1 => 1, 2 => 8, 3 => 27} squares.replace(cubes) squares # => {1=>1, 2=>8, 3=>27}  This is different from simply assigning the cubes hash to the squares variable name, because cubes and squares are still separate hashes.  They just happen to contain the same elements in the above example.  Changing cubes won't affect squares. cubes[4] = 64 squares # => {1=>1, 2=>8, 3=>27}  Hash#replace is useful for reverting a Hash to known default values.
  • 11. Removing elements from a Hash  To remove specific element from hash, pass the key into Hash#delete h = {} h[1] = 10 h # => {1=>10} h.delete(1) h # => {}  Don't try to delete an element from a hash by mapping it to nil.  It's true that, by default, you get nil when you look up a key that's not in the hash, but there's a difference between a key that's missing from the hash and a key that's present but mapped to nil.  Hash#has_key? will see a key mapped to nil, as will Hash#each and all other methods except for a simple fetch. h = {} h[5] # => nil h[5] = 10 h[5] # => 10 h[5] = nil h[5] # => nil h.keys # => [5] h.delete(5) h.keys # => []
  • 12. Example  Use the Hash#delete_if iterator to delete key-value pairs for which a certain code block returns true  Hash#reject works the same way, but it works on a copy of the Hash class Hash def delete_value(value) delete_if { |k,v| v == value } end end h = {'apple' => 'green', 'potato' => 'red', 'sun' => 'yellow', 'katydid' => 'green' } h.delete_value('green') h # => {"sun"=>"yellow", "potato"=>"red"}  The below code implements the opposite of Hash#merge; it extracts one hash from another class Hash def remove_hash(other_hash) delete_if { |k,v| other_hash[k] == v } end end squares = { 1 => 1, 2 => 4, 3 => 9 } doubles = { 1 => 2, 2 => 4, 3 => 6 } squares.remove_hash(doubles) squares # => {1=>1, 3=>9}  To wipe out the entire contents of a Hash, use Hash#clear
  • 13. Using an array or other modifiable object as hash key  A naive solution tends to lose hash values once the keys are modified coordinates = [10, 5] treasure_map = { coordinates => 'jewels' } treasure_map[coordinates] # => "jewels“ # Add a z-coordinate to indicate how deep the treasure is buried. coordinates << -5 coordinates # => [10, 5, -5] treasure_map[coordinates] # => nil  The easiest solution is to call the Hash#rehash method every time you modify one of the hash's keys treasure_map.rehash treasure_map[coordinates] # => "jewels"
  • 14. Continued… module ReliablyHashable def hash return object_id end end class ReliablyHashableArray < Array include ReliablyHashable end coordinates = ReliablyHashableArray.new([10,5]) treasure_map = { coordinates => 'jewels' } treasure_map[coordinates] # => "jewels“ # Add a z-coordinate to indicate how deep the treasure is buried. coordinates.push(-5) treasure_map[coordinates] # => "jewels"
  • 15. Continued…  The implementation of hash given in the previous solution violates the principle that different representations of the same data should have the same hash code.  This means that two ReliablyHashableArray objects will have different hash codes even if they have the same contents a = [1,2] b = a.clone a.hash # => 11 b.hash # => 11 a = ReliablyHashableArray.new([1,2]) b = a.clone a.hash # => -606031406 b.hash # => -606034266  The solution is to freeze your hash keys.  Any frozen object can be reliably used as a hash key, since you can't do anything to a frozen object that would cause its hash code to change
  • 16. Keeping multiple values for the same hash key hash = Hash.new { |hash, key| hash[key] = [] } raw_data = [ [1, 'a'], [1, 'b'], [1, 'c'], [2, 'a'], [2, ['b', 'c']], [3, 'c'] ] raw_data.each { |x,y| hash[x] << y } hash # => {1=>["a", "b", "c"], 2=>["a", ["b", "c"]], 3=>["c"]}  It's possible to subclass Hash to act like a normal hash until a key collision occurs, and then start keeping an array of values for the key that suffered the collision class MultiValuedHash < Hash def []=(key, value) if has_key?(key) super(key, [value, self[key]].flatten) else super end end end hash = MultiValuedHash.new raw_data.each { |x,y| hash[x] = y } hash # => {1=>["c", "b", "a"], 2=>["b", "c", "a"], 3=>"c"}
  • 17. Iterating over a hash  Note that each and each_pair return the key-value pairs in an apparently random order hash = { 1 => 'one', [1,2] => 'two', 'three' => 'three' } hash.each_pair { |key, value| puts "#{key.inspect} maps to #{value}"} # [1, 2] maps to two # "three" maps to three # 1 maps to one  Use Hash#each_key if you only need the keys of a hash active_toggles = { 'super' => true, 'meta' => true, 'hyper' => true } active_toggles.each_key { |active| puts active } # hyper # meta # super  Use Hash#each_value if you only need the values of a hash favorite_colors = { 'Alice' => :red, 'Bob' => :violet, 'Mallory' => :blue, 'Carol' => :blue, 'Dave' => :violet } summary = Hash.new(0) favorite_colors.each_value { |x| summary[x] += 1 } summary # => {:red=>1, :violet=>2, :blue=>2}
  • 18. Continued…  Don't modify the keyset of a hash during an iteration, or you'll get undefined results and possibly a RuntimeError 1.upto(100) { |x| hash[x] = true } hash.keys { |k| hash[k * 2] = true } # RuntimeError: hash modified during iteration  Using an array as intermediary hash = {1 => 2, 2 => 2, 3 => 10} hash.keys # => [1, 2, 3] hash.values # => [2, 2, 10] hash.to_a # => [[1, 2], [2, 2], [3, 10]]  Sorting the result of Hash#keys. extensions = { 'Alice' => '104', 'Carol' => '210', 'Bob' => '110' } extensions.keys.sort.each do |k| puts "#{k} can be reached at extension ##{extensions[k]}“ end # Alice can be reached at extension #104 # Bob can be reached at extension #110 # Carol can be reached at extension #210
  • 19. Continued…  Hash#sort and Hash#sort_by turn a hash into an array of two-element subarrays (one for each key-value pair), then sort the array of arrays however you like  This code sorts a to-do list by priority, then alphabetically to_do = { 'Clean car' => 5, 'Take kangaroo to vet' => 3, 'Realign plasma conduit' => 3 } to_do.sort_by { |task, priority| [priority, task] }.each { |k,v| puts k } # Realign plasma conduit # Take kangaroo to vet # Clean car  This code sorts a hash full of number pairs according to the magnitude of the difference between the key and the value transform_results = { 4 => 8, 9 => 9, 10 => 6, 2 => 7, 6 => 5 } by_size_of_difference = transform_results.sort_by { |x, y| (x-y).abs } by_size_of_difference.each { |x, y| puts "f(#{x})=#{y}: difference #{y-x}" } # f(9)=9: difference 0 # f(6)=5: difference -1 # f(10)=6: difference -4 # f(4)=8: difference 4 # f(2)=7: difference 5
  • 20. Iterating over a hash in insertion order  To iterate over a hash in the order in which the elements were added to the hash.  Use the orderedhash library require 'orderedhash‘ h = OrderedHash.new h[1] = 1 h["second"] = 2 h[:third] = 3 h.keys # => [1, "second", :third] h.values # => [1, 2, 3] h.each { |k,v| puts "The #{k} counting number is #{v}" } # The 1 counting number is 1 # The second counting number is 2 # The third counting number is 3  OrderedHash is a subclass of Hash that keeps an array of the keys in insertion order.  When you add key-value pair to the hash, OrderedHash modifies both the underlying hash and the array  But any operation that modifies an OrderedHash may also modify the internal array, so it's slower than just using a hash.  OrderedHash#delete is especially slow, since it must perform a linear search of the internal array to find the key being deleted.  Hash#delete runs in constant time, but OrderedHash#delete takes time proportionate to size of the hash.
  • 21. Inverting a hash  To switch the keys and values of hash phone_directory = { 'Alice' => '555-1212', 'Bob' => '555-1313', 'Mallory' => '111-1111' } phone_directory.invert # => {"111-1111"=>"Mallory", "555-1212"=>"Alice", "555-1313"=>"Bob"}  Hash#invert probably won't do what you want if your hash maps more than one key to the same value.  Only one of the keys for that value will show up as a value in the inverted hash phone_directory = { 'Alice' => '555-1212', 'Bob' => '555-1313', 'Carol' => '555-1313', 'Mallory' => '111-1111', 'Ted' => '555-1212' } phone_directory.invert # => {"111-1111"=>"Mallory", "555-1212"=>"Ted", "555-1313"=>"Bob"}  To preserve all the data from the original hash, write a version of invert that keeps an array of values for each key …
  • 22. Safe invert class Hash def safe_invert new_hash = {} self.each do |k,v| if v.is_a? Array v.each { |x| new_hash.add_or_append(x, k) } else new_hash.add_or_append(v, k) end end return new_hash end def add_or_append(key, value) if has_key?(key) self[key] = [value, self[key]].flatten else self[key] = value end end end phone_directory.safe_invert # => {"111-1111"=>"Mallory", "555-1212"=>["Ted", "Alice"], "555-1313"=>["Bob", "Carol"]} phone_directory.safe_invert.safe_invert # => {"Alice"=>"555-1212", "Mallory"=>"111-1111", "Ted"=>"555-1212", "Carol"=>"555-1313", "Bob"=>"555-1313"}
  • 23. Continued…  Ideally, if you called an inversion method twice you'd always get the same data you started with.  The safe_invert method does better than invert on this score, but it's not perfect.  If your original hash used arrays as hash keys, safe_invert will act as if you'd individually mapped each element in the array to the same value.  Call safe_invert twice, and the arrays will be gone.