How does this definition for a hash work? [duplicate] - ruby

This question already has answers here:
Is there any difference between the `:key => "value"` and `key: "value"` hash notations?
(5 answers)
Closed 8 years ago.
I found code with hash assignment such as follows:
#defeat = {r: :s, p: :r, s: :p}
# => {:r=>:s, :p=>:r, :s=>:p}
Why are the keys for this hash generated as symbols? Is this a short form of doing this?
defeat[:r] = :s
defeat[:p] = :r
defeat[:s] = :p
Is there a name for this style of Hash?

A Hash can be easily created by using its implicit form:
grades = { "Jane Doe" => 10, "Jim Doe" => 6 }
Hashes allow an alternate syntax form when your keys are always symbols. Instead of
options = { :font_size => 10, :font_family => "Arial" }
You could write it as:
options = { font_size: 10, font_family: "Arial" }
Now in your example #defeat = {r: :s, p: :r, s: :p}, all keys are symbol. That's why your example Hash is a valid construct, which has been introduced since 1.9.

When you use the hash style {key: value} you're actually declaring a symbol for the key. Like Arup's example, {:key => value} is the same thing with the implicit form. So anytime you use : instead of => in a hash, you are creating a symbol as the key.
In your example, you're creating symbols for both your key and your value.
{key: :value } # both are symbols

Related

why there is a column ":" in front of key in ruby [duplicate]

This question already has answers here:
Is there any difference between the `:key => "value"` and `key: "value"` hash notations?
(5 answers)
Closed 1 year ago.
aaa = { :one => "eins", :two => "zwei", :three => "drei" }
bbb = { one: "eins", two: "zwei", three: "drei" }
above are valid ruby code. at line 1, why there is ":" before "one"? What's the meaning?
It's called Symbol, you could think of it as a special string. Symbols are often used as hash keys.
You could check out more on Ruby Symbols vs. Strings
In ruby hash is an association of key and value.
my_hash = { :key => "value" }
or
my_hash = { key: "value" }
more informations here : https://launchschool.com/books/ruby/read/hashes

Ruby: what's the difference using property with colons and quotes

I'm a newbie on Ruby, just doing a fast upgrade in a existent project and I'm wondering what's the difference between object record and to_validate.
puts to_validated.class
# Hash
puts to_validated
# {"data"=>{"name"=>"david"}, "metadata"=>{"body_size"=>"16", "collector_ip"=>"172.22.0.1", "collector_timestamp"=>1579608324863, "event"=>"whatever", "version"=>"1.0"}}
puts record.class
# Hash
puts record
# {:data=>{"name"=>"david"}, :metadata=>{"body_size"=>"16", "collector_ip"=>"172.22.0.1", "collector_timestamp"=>1579610268940, "event"=>"default", "version"=>"1.0.0"}}
The only difference on those objects is colons on data and metadata. Is possible to convert colons into quotes?
I know it's a dumb question but I'm applying a fix in this project and using a third party library that is failing using record object.
You can use Hash.transform_keys which was introduced to Ruby in version 2.5 to change symbolized keys into strings:
record.transform_keys { |k| k.to_s }
In Ruby hashes are a key value data structure. The keys can actually be a mix of any kind of objects:
hash_with_numerical_keys = {
1 => 'A',
2 => 'B',
3 => 'C'
3.5 => 'D'
}
hash_with_string_keys = {
'a' => 1,
'b' => 2,
'c' => 3
}
hash_with_symbols = {
:a => 1,
:b => 2,
:c => 3
}
# can also be declared as
hash_with_symbols = {
a: 1,
b: 2,
c: 3
}
hash_with_singletons = {
nil => 0,
true => 1,
false => 2
}
Symbols are commonly used as only one instance of a symbol ever exists. They are thus really effective to compare. String keys mostly come into play when you're dealing with JSON or some kind of external data.
The hash you are looking at contains a mixture of string and symbol keys:
{:data=>{"name"=>"david"}, :metadata=>{"body_size"=>"16", "collector_ip"=>"172.22.0.1", "collector_timestamp"=>1579610268940, "event"=>"default", "version"=>"1.0.0"}}
In Ruby 2.5 you can use hash#transform_keys to change the keys into strings:
hash.transform_keys(&:to_s)
In earlier versions you can do:
hash.each_with_object({}) do |(k,v), new_hash|
new_hash[k.to_s] = v
end
If you are using Rails or just ActiveSupport you can use Hash#stringify_keys, Hash#deep_stringify_keys or HashWithIndifferentAccess

How to access a symbol hash key using a variable in Ruby

I have an array of hashes to write a generic checker for, so I want to pass in the name of a key to be checked. The hash was defined with keys with symbols (colon prefixes). I can't figure out how to use the variable as a key properly. Even though the key exists in the hash, using the variable to access it results in nil.
In IRB I do this:
>> family = { 'husband' => "Homer", 'wife' => "Marge" }
=> {"husband"=>"Homer", "wife"=>"Marge"}
>> somevar = "husband"
=> "husband"
>> family[somevar]
=> "Homer"
>> another_family = { :husband => "Fred", :wife => "Wilma" }
=> {:husband=>"Fred", :wife=>"Wilma"}
>> another_family[somevar]
=> nil
>>
How do I access the hash key through a variable? Perhaps another way to ask is, how do I coerce the variable to a symbol?
You want to convert your string to a symbol first:
another_family[somevar.to_sym]
If you want to not have to worry about if your hash is symbol or string, simply convert it to symbolized keys
see: How do I convert a Ruby hash so that all of its keys are symbols?
You can use the Active Support gem to get access to the with_indifferent_access method:
require 'active_support/core_ext/hash/indifferent_access'
> hash = { somekey: 'somevalue' }.with_indifferent_access
=> {"somekey"=>"somevalue"}
> hash[:somekey]
=> "somevalue"
> hash['somekey']
=> "somevalue"
Since your keys are symbols, use symbols as keys.
> hash = { :husband => 'Homer', :wife => 'Marge' }
=> {:husband=>"Homer", :wife=>"Marge"}
> key_variable = :husband
=> :husband
> hash[key_variable]
=> "Homer"
If you use Rails with ActiveSupport, then do use HashWithIndifferentAccess for flexibility in accessing hash with either string or symbol.
family = HashWithIndifferentAccess.new({
'husband' => "Homer",
'wife' => "Marge"
})
somevar = "husband"
puts family[somevar]
#Homer
somevar = :husband
puts family[somevar]
#Homer
The things that you see as a variable-key in the hash are called Symbol is a structure in Ruby. They're primarily used either as hash keys or for referencing method names. They're immutable, and Only one copy of any symbol exists at a given time, so they save memory.
You can convert a string or symbol with .to_sym or a symbol to string with .to_s to illustrate this let me show this example:
strings = ["HTML", "CSS", "JavaScript", "Python", "Ruby"]
symbolArray = [:HTML, :CSS, :JavaScript, :Python, :Ruby]
# Add your code below!
symbols = Array.new
strings.each {|x|
symbols.push(x.to_sym)
}
string = Array.new
symbolArray .each {|x|
string.push(x.to_s)
}
print symbols
print string
the result would be:
[:HTML, :CSS, :JavaScript, :Python, :Ruby]
["HTML", "CSS", "JavaScript", "Python", "Ruby"]
In ruby 9.1 you would see the symbols with the colons (:) in the right instead:
movies = { peter_pan: "magic dust", need_4_speed: "hey bro", back_to_the_future: "hey Doc!" }
I just wanted to make this point a litter more didactic so who ever is reading this can used.
One last thing, this is another way to solve your problem:
movie_ratings = {
:memento => 3,
:primer => 3.5,
:the_matrix => 3,
}
# Add your code below!
movie_ratings.each_key {|k|
puts k.to_s
}
result:
memento
primer
the_matrix

Hash declaration syntax error in irb

1. { :a => 10 } #=> no error
2. { a: 10 } #=> no error
3. { :"str" => 10 } #=> no error
4. { "str": 10 } #=> syntax error, unexpected ':', expecting =>
Isn't 4. same as 2? Why 2 is working and 4 throws syntax error?
My understanding is that {"key": value} is not a valid syntax as it is not clear whether it means {:"key" => value} or {"key" => value}
There is a discussion on this here. Quote from Matz in the discussion
| Iff {'key': 'value'} means {:key => 'value'} I have no objection.
| Won't that be misleading? I think the OP wants {'key': 'value'} to mean {'key' => 'value}
But considering the fact that {key: "value"}
is a shorthand for {:key => "value"}, {"key": "value"} should be a
shorthand for {:"key" => "value"}. Besides that, since it reminds me
JSON so much, making a: and "a": different could cause more confusion
than the above misleading.
matz.
Hash: Hashes allow an alternate syntax form when your keys are always symbols.
options = { :font_size => 10, :font_family => "Arial" }
You could write it as:
options = { font_size: 10, font_family: "Arial" }
In your first 3 cases all are symbols in key position,but the fourth is a string instance,not the symbol instance as key.That's the reason 4th case is invalid Ruby syntax.
{ :a => 10 }.keys[0].class # => Symbol
{ a: 10 }.keys[0].class # => Symbol
{ :"str" => 10 }.keys[0].class # => Symbol
No. (1) is standard symbol, (2) is shorthand 1.9 syntax for symbol-key hashes, (3) is shorthand for "str".to_sym, (4) does not exist and you should use the hashrocket.

Specifying default value for Hash of hashes in Ruby [duplicate]

This question already has answers here:
Strange, unexpected behavior (disappearing/changing values) when using Hash default value, e.g. Hash.new([])
(4 answers)
Closed 5 years ago.
Lets say I have a Hash called person whose key is name and value is a hash having keys 'age' and 'hobby'. An entry in the hash person would look like
=> person["some_guy"] = {:hobby => "biking", :age => 30}
How would I go about specifying the default for the hash 'person'? I tried the following
=> person.default = {:hobby => "none", :age => 20}
but it doesn't work.
EDIT:
I was setting one attribute and expecting others to be auto-populated. For eg.
=> person["dude"][:age] += 5
and this is what I was seeing
=> person["dude"]
=> {:hobby => "none", :age => 25}
which is fine. However, typing person at the prompt, I get an empty hash.
=> person
=> {}
However, what I was expecting was
=> person
=> {"dude" => {:hobby => "none", :age => 25}}
Why It May Not Work for You
You can't call Hash#default if an object doesn't have the method. You need to make sure that person.is_a? Hash before it will work. Are you sure you don't have an array instead?
It's also worth noting that a hash default doesn't populate anything; it's just the value that's returned when a key is missing. If you create a key, then you still need to populate the value.
Why It Works for Me
# Pass a default to the constructor method.
person = Hash.new({hobby: "", age: 0})
person[:foo]
=> {:hobby=>"", :age=>0}
# Assign a hash literal, and then call the #default method on it.
person = {}
person.default = {hobby: "", age: 0}
person[:foo]
=> {:hobby=>"", :age=>0}
What You Probably Want
Since hash defaults only apply to missing keys, not missing values, you need to take a different approach if you want to populate a hash of hashes. One approach is to pass a block to the hash constructor. For example:
person = Hash.new {|hash,key| hash[key]={hobby: nil, age:0}}
=> {}
person[:foo]
=> {:hobby=>nil, :age=>0}
person[:bar]
=> {:hobby=>nil, :age=>0}
person
=> {:foo=>{:hobby=>nil, :age=>0}, :bar=>{:hobby=>nil, :age=>0}}
You can specify a hash's default value on instantiation by passing the default value to the .new method:
person = Hash.new({ :hobby => '', :age => 0 })
You can use Hash#default_proc to initialise a hash with default values dynamically.
h = Hash.new
h.default_proc = proc do |hash, key|
hash[key] = Hash.new(0) unless hash.include? key
end
h[0][0] # => 0
h[1][0] # => 0
h[0][0] = 1
h[0][0] # => 1
h[1][0] # => 0

Resources