I am drowning in the million ways to access Hash.
condition1 = {
"e" =>1
}
condition2 = {
"e":1
}
condition3 = {
:"e" =>3
}
condition4 = {
e:4
}
condition5 = { # 100% sure not working because of syntax error
e=>5
}
condition6 = { # 100% sure not working because of syntax error
:e:6
}
condition7 = {
:e=>7
}
puts condition1["e"]
puts condition2["e"]
puts condition3[:e]
puts condition4[:e]
puts condition7[:e]
Output:
1
(nothing)
3
4
7
First question: For the first 2 puts statement, why is it working for the first one but not the second one? In both hashes, I am using Strings as keys. Is it because I used "=>" in the first Hash and thus the string is actually being read as Symbols? So it is actually being processed like :"e" =>1?
Second question: That leads to my second question about the third condition, I was told that if I used Symbol sign before a quote, what happens in the background is that the quote will be ignored. That's why I was able to access it through simply :e without the quotes. Is that true? However if that's true, then the first question becomes more confusing. If in the first condition, "e"=>1 was evaluated as :"e" =>1, then shouldn't the quotes be ignored? Thus eventually it's read as :e =>1. Then how come I was able to access it with only the quotes?
Third question: So how do I access the second condition? I know it's not recommended to use strings as key values. However what if in a certain case I have already created it with strings, how do I access it? I have tried accessing it through a variable name but it's still not outputing anything.
Thank you so much for reading this. I know it's definitely not worth it to care too much about these details. But I ran into it today and can't really move on without figuring out what the HECK is going on !!
In Ruby, symbols are immutable names primarily used as hash keys or for referencing method names. Hashes and Symbols. Lesson 1 of 2. The Story So Far. Recall that hashes are collections of key-value pairs, where a unique key is associate…
In Ruby, the values in a hash can be accessed using bracket notation. After the hash name, type the key in square brackets in order to access the value.
Symbols are most commonly used as placeholders in Hashes. We have used symbols already in Rails, for example the Rails params hash associates any the values of any parameters passed in by the user (from a form or in the url) with a symbol representing the name of that value.
In Ruby you can create a Hash by assigning a key to a value with => , separate these key/value pairs with commas, and enclose the whole thing with curly braces.
If there's a colon (
:
) it's a Symbol. If there's a hashrocket (=>
), it's whatever is to the left of the hashrocket (which can be anything).
When we say "Hash literal" we mean code that declares a Hash with curly braces ({ foo: 1 }
) or as method arguments (bar(baz: 2)
).
There are two ways to declare a key in a Hash literal.
=>
)The first way to declare a key is with the hashrocket (=>
). When you use the hashrocket, the key is whatever value is to the left of it, and you can put any kind of object (or expression) to the left of it:
hashrocket_hash = {
"I am a String" => 1,
:I_am_a_Symbol => 2,
:"I am also a Symbol" => 4,
/I am a Regexp!/ => 5,
Kernel => 6,
if true then "I am also a String" end => 7,
nil => 8
}
p hashrocket_hash.keys
# => [ "I am a String",
# :I_am_a_Symbol,
# :"I am also a Symbol",
# /I am a Regexp!/,
# Kernel,
# "I am also a String",
# nil
# ]
p hashrocket_keys.map(&:class)
# => [ String,
# Symbol,
# Symbol,
# Regexp,
# Module,
# String,
# NilClass
# ]
:
)The other way to declare a key is with a colon (:
). When you use a colon the resulting key is always a Symbol. The usual Symbol rules apply (read the very thorough answer here: What can a ruby symbol (syntax) contain?) except the colon goes at the end instead of the beginning:
colon_hash = {
I_am_a_Symbol: 9,
"I am also a Symbol": 10
}
p colon_hash.keys
# => [ :I_am_a_Symbol,
# :"I am also a Symbol" ]
p colon_hash.keys.map(&:class)
# => [ Symbol,
# Symbol ]
There are no special rules for accessing a Hash value. If you want to access a value whose key is a Symbol, you must use a Symbol. If you want to access a value whose key is a String, you must use a String. If the key is something else, you must use that thing.
In the below examples, pay close attention to which keys are followed by colons and which are followed by hashrockets:
hsh1 = { foo: 1 }
p hsh1[:foo] # => 1
p hsh1[:"foo"] # => 1
p hsh1["foo"] # => nil
hsh2 = { "bar": 2 }
p hsh2[:bar] # => 2
p hsh2[:"bar"] # => 2
p hsh2["bar"] # => nil
hsh3 = {
Kernel: 3,
Kernel => 4
}
p hsh3[:Kernel] # => 3
p hsh3[Kernel] # => 4
p hsh3["Kernel"] # => nil
Your confusion is caused by 2 causes, first, the syntax of symbol literal, and the second, the syntax of hash literal.
The most basic form of a symbol is :hello_world
.
However, in order to allow symbol literals contain special characters, ruby introduces this syntax: :'hello-world'
or :"hello-world"
.
Unlike JSON objects in javascript which only allows strings to be the keys, ruby allows anything to serve as a hash key, so the basic form of a hash is
{
key1 => value1,
key2 => value2,
...
}
Notice that key1
, key2
and value1
, value2
are just placeholders. You can replace them with anything, which can be:
So when using symbol literals as keys and Fixnum
literals as values, the basic form is
{:e => 1}
or
{:"e" => 1}
or
{:'e' => 1}
Because symbol literals are often used as hash keys (because they are immutable), Ruby introduced a shorthand version of this specific case: moving the :
to the tail of the key, and omit the =>
.
{e: 1}
or
{'e': 1}
or
{"e": 1}
Note that there must not be any spaces between e
and :
, otherwise there is a syntax error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With