HomeSearch

Ruby Hash Examples

Use the Hash class to store keys and values. Hash enables fast lookups.

Hash.

A hash is an optimized collection. It stores keys and values. We use keys to access the values—this is called a hash lookup. The Hash class provides this function in Ruby.

With a hash,

we can add, remove and enumerate values. These lookup tables are powerful. They can be combined with Arrays to solve complex problems.

New example.

A hash is created by calling Hash.new(). In this example, we pass no argument to new. The hash has no special default value when a key is not found.

First: We add 3 string keys that have integer values. Theses are key-value pairs.

Brackets: We use the square brackets, "[" and "]" to specify the key. The value we add is indicated by assignment.

Ruby program that creates a hash # Create a new hash. items = Hash.new() # Store these key-value pairs in it. items["milk"] = 5 items["eggs"] = 10 items["bread"] = 15 # Display the values. puts items["milk"] puts items["eggs"] puts items["bread"] Output 5 10 15

Default value.

A hash can have a custom default value. This is returned when a nonexistent key is accessed. Here we try to access a key that does not exist. The hash returns -1.

Also: We use values of type integer (32) and of type string ("medium") in the hash. A hash is flexible and can contain different types.

Ruby program that uses default value # Use the default value of -1. sizes = Hash.new(-1) # Add keys and values. sizes["jeans"] = 32 sizes["shirt"] = "medium" # Access existing data. puts sizes["jeans"] puts sizes["shirt"] # This doesn't exist. puts sizes["jacket"] Output 32 medium -1

Count, delete.

In this example, we use the count() method—this returns the number of keys in the collection. We then use the delete() method to remove a key and its value.

Note: Before the delete() method is called, there are four elements. After it is invoked, there are only three.

Ruby program that uses count, delete # Add data to the new hash. elements = Hash.new() elements[100] = "a" elements[200] = "b" elements[300] = "c" elements[400] = "d" # Display count. print "Count: ", elements.count(), "\n" # Delete a key and its value. elements.delete(100) # Display new count. print "Count: ", elements.count(), "\n" Output Count: 4 Count: 3

Delete_if.

This method receives a block argument. In the block, the keys and values are evaluated in pairs. We must return true or false based on the key and value.

Here: We delete keys of length greater than 3. The key "rabbit" is deleted, but the other two ("cat" and "dog") remain.

Note: We can also delete based on the value. Just test the second parameter in the block.

Ruby program that uses delete_if # A hash with three pairs. values = {"cat" => 1, "dog" => 2, "rabbit" => 4} # Delete keys longer than 3 chars. values.delete_if{|key, value| key.length > 3} puts values Output {"cat"=>1, "dog"=>2}

Loop, keys.

A for-loop can be used over the keys in a Hash. We call the keys() method on the hash variable in the for-loop statement. We must then access the value with a lookup.
Ruby program that uses keys, for-loop # Add names. names = Hash.new() names["charlotte"] = "stant" names["maggie"] = "verver" names["adam"] = "verver" # Use for-loop on keys. for key in names.keys() print key, "/", names[key], "\n" end Output charlotte/stant maggie/verver adam/verver

Each.

With this iterator, we loop over each pair in a hash. We must declare two variables. We use the names key and value for them. This is the current key and value in the hash.

Do: The each iterator requires the "do" keyword if you do not place the entire statement on one line.

Each_pair: The each_pair method is aliased to each. There is no advantage in using it. In my experience, each is more standard.

Ruby program that uses each, hash numbers = {10 => 100, 20 => 200, 30 => 300} # Use each to enumerate the pairs in the hash. numbers.each do |key, value| # Display the key and value. print " KEY: ", key, "\n" print "VALUE: ", value, "\n" end Output KEY: 10 VALUE: 100 KEY: 20 VALUE: 200 KEY: 30 VALUE: 300

One-line syntax.

We do not need multiple lines to use each over a hash. Here we use the each method on a hash with a block contained by curly brackets. We print the keys and values.
Ruby program that uses each, one-line numbers = {100 => "A", 200 => "B", 300 => "C"} # Use each with one-line syntax. numbers.each {|k, v| print k, " ", v, "\n"} Output 100 A 200 B 300 C

Empty.

With count() we can see if a hash is empty by checking it for zero elements. But the "empty?" method is another syntax for this check. If it returns true, the hash has no elements.

Tip: In some program logic, testing to see if a hash is empty may help performance. We can avoid testing for specific keys.

Ruby program that uses empty method # New hash. items = Hash.new() # Check emptiness. if items.empty? puts "Empty" end # Add something. items["sam"] = 1 # It is no longer empty. if !items.empty? puts "Not empty" end Output Empty Not empty

Merge.

It is sometimes necessary to combine (union, or merge) two hashes into one. This puts all distinct keys from both hashes into a single hash. Duplicates are removed.

Duplicates: The resulting merged hash has only one value for "b"—this is 2. But in the hashes, the key "b" has two values, 2 and 3.

So: The duplicate value was lost in the merged hash. This could be a problem if there are two valid values.

Ruby program that merges hashes # Two input hashes. one = Hash["a" => 1, "b" => 2] two = Hash["b" => 3, "c" => 0, "d" => 3] # Merge them into a third. both = two.merge(one) # Display result. puts both Output {"b"=>2, "c"=>0, "d"=>3, "a"=>1}

Invert.

In a hash, each key points to one value. We can quickly access keys, but not values. To efficiently access values, we can use the invert() method to create an inverted hash.

Then: We can use a fast lookup on a value to get its original key. And this optimizes certain program requirements.

Ruby program that inverts a hash # Create a hash and invert it. one = Hash["a" => 1, "b" => 2] two = one.invert() # Display both hashes. puts one puts two Output {"a"=>1, "b"=>2} {1=>"a", 2=>"b"}

Keys.

How can we test a key for existence? In Ruby, the "key?" and "has_key?" methods are effective. These methods, which have the same functionality, return true or false.

Note: These methods are fast—they just perform a lookup. Two methods in Ruby, member and include, are equivalent.

Ruby program that checks keys for existence # A hash of utensils silverware = Hash["spoon" => 10, "fork" => 20] # See if key exists. if silverware.key?("fork") puts "Found: fork" end # Check that key does not exist. if !silverware.has_key?("knife") puts "Not found: knife" end Output Found: fork Not found: knife

Flatten.

Sometimes we want to place a hash's pairs into an array. Flatten() has this effect. It places keys and values into a single array. The ordering of key, then value, is retained.

Tip: Flatten has the same effect as calling keys() and values() and then combining the two into a third array.

However: It is better to use flatten() when this combined data structure is required—it is simpler.

Ruby program that calls flatten # Create and flatten a hash. numbers = Hash[1 => 10, 2 => 20, 3 => 30] flat = numbers.flatten() # Display flattened array. puts flat Output 1 10 2 20 3 30

Eql method.

Next, the "eql?" method compares two hashes for exact content equality. It checks all keys and all values. If any difference is found, "eql?" returns false.

Here: Three hashes are created. The first hash, fruit1, is equal to the third hash, fruit3. But the second hash is not equal.

Ruby program that uses eql # Create three hashes. fruit1 = Hash["apple" => 1, "pear" => 2] fruit2 = Hash["guava" => 3, "apricot" => 4] fruit3 = Hash["pear" => 2, "apple" => 1] # See if first hash equals second hash. if !fruit1.eql?(fruit2) puts "1 not equal to 2" end # First hash equals third hash. # ... Ordering does not matter. if fruit1.eql?(fruit3) puts "1 equals 3" end Output 1 not equal to 2 1 equals 3

Inspect.

A hash is converted to a string with inspect(). This is helpful when we want to store string representations in a file or in memory.

Note: With inspect(), we can make further changes to the hash but keep the same string.

Characters: The string representation returned by inspect() uses the => characters to separate keys and values.

Ruby program that uses inspect # An input hash. values = ["a" => 10, "b" => 20]; # Convert to string. s = values.inspect # Display the string. puts s # String length. puts s.length Output [{"a"=>10, "b"=>20}] 20

Nested.

A hash can contain other hashes. We can then access items by chaining lookups. This allows us to create a tree-like data structure. For small nested lookups, this is effective.

Here: We create a hash with two nested hashes in it. Then we perform lookups on the hash located at "cat" and the one at "dog."

Ruby program that uses nested hash lookup = Hash[] # Create and add a subhash. subhash = Hash[] subhash["paws"] = 4 subhash["fur"] = "orange" lookup["cat"] = subhash # Create another subhash. subhash = Hash[] subhash["tail"] = 1 subhash["ears"] = 2 lookup["dog"] = subhash # Display nested hashes. puts lookup["cat"] puts lookup["dog"] # Get values from nested hashes. puts lookup["cat"]["paws"] puts lookup["dog"]["ears"] Output {"paws"=>4, "fur"=>"orange"} {"tail"=>1, "ears"=>2} 4 2

Performance.

One goal of Hash is to improve performance. When a lookup is done, a hash code is computed. This estimates the element's location in memory and speeds searching.

Here: We test lookups in a hash. Then we search for those same elements in a similar Array.

In the results: We find Hash improves performance. Even on a small collection of five elements, it locates about 50% faster than an array.

Caution: Performance of high-level languages (like Ruby) is hard to measure. Benchmarks quickly become outdated as implementations change.

Ruby program that times hash, array h = Hash["one" => 0, "two" => 1, "three" => 2, "four" => 3, "five" => 4] a = Array["one", "two", "three", "four", "five"] count = 100000 n1 = Time.now.usec count.times do # Two hash lookups. v = h["four"] v = h["two"] end n2 = Time.now.usec count.times do # Two array find operations. v = a.index("four") v = a.index("two") end n3 = Time.now.usec # Compute milliseconds total. puts ((n2 - n1) / 1000) puts ((n3 - n2) / 1000) Output 55 ms Hash lookup 86 ms Array index

Sort.

A hash can be sorted. When we call sort on it, Ruby converts it into a sortable array of key-value pairs. By default, the keys are sorted, in ascending order (from lowest to highest).
Ruby program that sorts on keys plants = {"carrot" => 5, "turnip" => 10, "apple" => 8} # Sort the hash by its keys. plants.sort.each do |key, value| # Display the entry. puts key + ": " + String(value) end Output apple: 8 carrot: 5 turnip: 10

Sort on values.

We can also use the sort method to create an array sorted by a hash's values. We specify a block with sort. In it, we compare the second element in each pair (at index 1).

Note: There is no in-place sorting method on a hash. Calling "sort!" causes an error. We must always copy into a new variable.

Ruby program that sorts on values plants = {"carrot" => 5, "turnip" => 10, "apple" => 8} # Sort the hash by its values. # ... Iterate over the resulting array. result = plants.sort{|x, y| x[1] <=> y[1]} result.each do |key, value| puts String(value) + "..." + key end Output 5...carrot 8...apple 10...turnip

Detect duplicates.

The hash detects duplicates—each key is unique. With a hash, we can find the duplicates in an array. This is fast even on arrays with many elements.Remove Duplicates

A discussion.

We often have a choice of data structures. If lookups predominate, a hash is fastest. If elements must be unique, a hash is also easiest—it detects duplicates.

A summary.

The Hash class is a key part of Ruby. It is part of the core library, which makes it simple to use. It can have keys and values of many types.
Home
Dot Net Perls
© 2007-2019 Sam Allen. All rights reserved. Written by Sam Allen, info@dotnetperls.com.