詳細検索

I tried to summarize Ruby's confusing arrays, hashes, and symbols.

Avatar
by maeno
5 min read

I tried to summarize Ruby's confusing arrays, hashes, and symbols.
Translated from 日本語 • View original

Happy New Year everyone.

Well, I think I'll start my first post in 2015 with the hottest Ruby story right now.

First of all, as a basic review, there are two types of arrays in Ruby: the 'array' class object, which is a one-dimensional array, and the 'hash' class object, which is a multi-dimensional array (associative array). Each array object is distinguished by a literal symbol that encloses the element when defined:

array = ["A", "B", "C"] # Define array variable array
hash1 = {:first=> "A", :second=> "B", :third = > "C"} # define hash hash1

The 'array' class object, which is a one-dimensional array, automatically assigns a numeric subscript to each element value, so that each element can be accessed by the numeric subscript index.

array = ["A", "B", "C"]
puts array[0] # "A" is displayed

On the other hand, the 'hash' class object is a key-value object, so you can access the element value with a string-type subscript (key).

hash2 = {"first" => "A", "second" => "B", "third" => "C"}
puts hash2["first"] # "A" is displayed

Now, have you noticed that the hash1 and hash2 defined in the very first example here specify the keys differently? hash1 and hash2 have the same element value, but they are not the same hash because they have different keys.

puts hash1 == hash2 # false

hash1 is a hash with a hash key as a symbol, and hash2 is a hash with a string as the key, so each is a different hash. Note that the key of the hash, whether it is a symbol or a string, must be unique within the hash. Also, if you mix string keys and symbols with the same name, each element is treated as something else.

hash3 = {:element => "A", :element => "B"}
hash4 = {"element" => "A", "element" => "B", :element => "A"}
puts hash3 # {:element=>"B"}
puts hash4 # {"element"=>"B", :element=>"A"}

If you use a hash key as a symbol, you can shorten the assignment expression.

hash5 = {:first => "A", :second => "B"}
hash6 = {first: "A", second: "B"}
puts hash5 == hash6 # true

The way to write hash6 is familiar with JavaScript and CSS expressions, so it may be easy to use for those who have coded them. To get the element value of a hash of a symbolic type:

puts hash5[:first] # "A"
puts hash6[:second] # shows "B"

When I first saw Ruby code, I was quite confused because I didn't understand that the hash literal (the prefix ":"" character) was preceded or followed by a symbolic hash assignment. So, I often used the PHP-like hash of the string key, which was the most familiar and easy to understand.

However, hashes are faster to execute with symbols.

Therefore, if you can use symbols, it is better to use hash keys as symbols. Then, if you want to generate a hash, you can use the key of the symbol all the way. ──You may think. However, there are letters in the names of symbols that cannot be used. A typical example is "-(hyphen)".

hash7={:first-element=> "A"} # This will result in an error
hash8 = {:"first-element" => "A"} # The entire string containing "" is the symbol
hash9 = {:first_element => "A", :secondElement => "B", :secondelement => 2}
puts hash9 # {:first_element=>"A", :secondElement=>"B", :secondelement=>2}

It is enough to recognize the characters that can be used as characters with the symbol "_ (underscore)" added to the half-width alphanumeric characters. Please note that the case of the half-width alphabet is sensitive, and half-width numbers cannot be the first letter of the symbol name.

However, even if there are characters that cannot be used, it is best to avoid using string keys for hash keys as much as possible. This is because symbols are unique objects that can maintain their uniqueness even if destructive methods are used externally. In other words, the key information of the hash does not change no matter what, so the hash structure has the advantage of maintaining regularity both inside and outside the application (well, it's only a metaphysical benefit...).

For example, let's consider what it would be like to take out only the hash key and perform the processing with a destructive method...

hash10 = {"element" => "A", :element => "B"}
for i in 1..3
  hash10.keys.each do |key|
    puts key.upcase.object_id
  end
end
------
22462512 # Object ID of the string key "element" (for loop 1st)
217508 # Symbol key: element's object ID (for loop 1)
22460736 # Object ID of the string key "element" (for loop 2nd)
217508 # Symbol key: element's object ID (for loop 2nd)
22460484 # Object ID of the string key "element" (for loop 3rd)
217508 # Symbol key: element's object ID (for loop 3rd)

This involves capitalizing the hash key with the 'upcase' method three times. All the keys of the expanded hash (the value of the variable key) are converted to 'ELEMENT', but in the case of string keys, the object ID changes every time the 'upcase' method is called. In other words, it is recognized as a different object internally in the system. On the other hand, in the case of symbol keys, the object ID does not change no matter how many times the 'upcase' method is called. The symbol ":element" in the system is kept unique.

If I were to rephrase the symbol in an easy-to-understand way, would it be "global variable string constant object"? (On the other hand, it may be difficult to understand...)

──Anyway, I thought it would be better to understand the symbols before handling Ruby hashes.

Related Articles