In Ruby, what does a hash followed by rectangular brackets do? - ruby

In Ruby, what does a hash followed by rectangular brackets do? example ->
quantity = { :buy => 1, :sell => -1}[action.to_sym]

It's equivalent to
hash = { :buy => 1, :sell => -1}
quantity = hash[action.to_sym]
It works also for arrays or string:
['a', 'b', 'c'][1] # -> 'b'
'abc'[1] # -> 'b'

It returns the value (what is on the right side of the arrow =>) that corresponds to the key (what is on the left side of the arrow) given in []. For example, if action.to_sym turns out to be :buy, then quantity will be 1.

Any peace of code in ruby has object result. So { :buy => 1, :sell => -1} gives hash object with keys and values. Hash it is the data structure that has keys and values. You can get value by key through brackets like this: hash[:buy]. So you have hash object here after { :buy => 1, :sell => -1} and you gets value by key action.to_sym

Related

How do I find the value of the key that I set with argument in Ruby?

I am currently working on a project with Ruby.
I don't know how to find the set of the value and key that has the same key as I gave with argument.
what I have tried is something like this below.
but it doesn't work.
def find_target(type)
target = type_list.find{|k,v| k == type}
target
end
def type_list
type = {
a: 1,
b: 2,
c: 3,
d: 4
}
type
end
but instead of giving an argument of variable, I gave a string as an argument, and it worked.
def find_target(a)
target = type_list.find{|k,v| k == a}
target
end
Edited
What I really want find_target to do is returning a matched value.
For example, when an argument is a, then it returns 1.
How can I solve this?
I would love you if you could help me.
Thank you .
I think one thing tripping you up is that your type_list hash is keyed with symbols (rather than strings or the value of a variable). The syntax you're using:
{a: 1}
is just shorthand for this:
{:a => 1}
Which means "A Hash with one key: the symbol :a with the value 1". That's distinct from:
{'a' => 1} # Keyed with the string 'a'
and this:
a = 'something'
b = {a => 1} # Keyed with value of 'a' at the time of creating, ie: {'something' => 1}. Note that if you change the value of a, the hash key won't change.
What do you expect as your return value from find_target(:a)? The find method on a Hash will return an Enumerator - mostly equivalent to a two-element Array, with the key and the value: {a: 1}.find{|k,v|k == :a} will return [:a, 1]. Is that what you want?
If you just want to have the value 1 returned, then you're really doing a hash lookup, and you don't need any extra methods at all. A common way to do this would be to define type_list as a constant, and then just refer to it by key:
TYPE_LIST = {
a: 1,
b: 2,
c: 3,
d: 4
}
#Then to find the type:
TYPE_LIST[:a] # Returns '1'
You might want to use a find_type method to handle the case where the key doesn't match a type: a plain Hash lookup will return nil, which you might not want.
Hope this helps put you on the right path, but I'm happy to expand this answer if needed!

Ruby how to return an element of a dictionary?

# dictionary = {"cat"=>"Sam"}
This a return a key
#dictionary.key(x)
This returns a value
#dictionary[x]
How do I return the entire element
"cat"=>"Sam"
#dictionary
should do the trick for you
whatever is the last evaluated expression in ruby is the return value of a method.
If you want to return the hash as a whole. the last line of the method should look like the line I have written above
Your example is a bit (?) misleading in a sense it only has one pair (while not necessarily), and you want to get one pair. What you call a "dictionary" is actually a hashmap (called a hash among Rubyists).
A hashrocket (=>) is a part of hash definition syntax. It can't be used outside it. That is, you can't get just one pair without constructing a new hash. So, a new such pair would look as: { key => value }.
So in order to do that, you'll need a key and a value in context of your code somewhere. And you've specified ways to get both if you have one. If you only have a value, then:
{ #dictionary.key(x) => x }
...and if just a key, then:
{ x => #dictionary[x] }
...but there is no practical need for this. If you want to process each pair in a hash, use an iterator to feed each pair into some code as an argument list:
#dictionary.each do |key, value|
# do stuff with key and value
end
This way a block of code will get each pair in a hash once.
If you want to get not a hash, but pairs of elements it's constructed of, you can convert your hash to an array:
#dictionary.to_a
# => [["cat", "Sam"]]
# Note the double braces! And see below.
# Let's say we have this:
#dictionary2 = { 1 => 2, 3 => 4}
#dictionary2[1]
# => 2
#dictionary2.to_a
# => [[1, 2], [3, 4]]
# Now double braces make sense, huh?
It returns an array of pairs (which are arrays as well) of all elements (keys and values) that your hashmap contains.
If you wish to return one element of a hash h, you will need to specify the key to identify the element. As the value for key k is h[k], the key-value pair, expressed as an array, is [k, h[k]]. If you wish to make that a hash with a single element, use Hash[[[k, h[k]]]].
For example, if
h = { "cat"=>"Sam", "dog"=>"Diva" }
and you only wanted to the element with key "cat", that would be
["cat", h["cat"]] #=> ["cat", "Sam"]
or
Hash[[["cat", h["cat"]]]] #=> {"cat"=>"Sam"}
With Ruby 2.1 you could alternatively get the hash like this:
[["cat", h["cat"]]].to_h #=> {"cat"=>"Sam"}
Let's look at a little more interesting case. Suppose you have an array arr containing some or all of the keys of a hash h. Then you can get all the key-value pairs for those keys by using the methods Enumerable#zip and Hash#values_at:
arr.zip(arr.values_at(*arr))
Suppose, for example,
h = { "cat"=>"Sam", "dog"=>"Diva", "pig"=>"Petunia", "owl"=>"Einstein" }
and
arr = ["dog", "owl"]
Then:
arr.zip(h.values_at(*arr))
#=> [["dog", "Diva"], ["owl", "Einstein"]]
In steps:
a = h.values_at(*arr)
#=> h.values_at(*["dog", "owl"])
#=> h.values_at("dog", "owl")
#=> ["Diva", "Einstein"]
arr.zip(a)
#=> [["dog", "Diva"], ["owl", "Einstein"]]
To instead express as a hash:
Hash[arr.zip(h.values_at(*arr))]
#=> {"dog"=>"Diva", "owl"=>"Einstein"}
You can get the key and value in one go - resulting in an array:
#h = {"cat"=>"Sam", "dog"=>"Phil"}
key, value = p h.assoc("cat") # => ["cat", "Sam"]
Use rassoc to search by value ( .rassoc("Sam") )

Replace keys with values in a Hash

What is the best way to replace all keys with values in a hash?
I came up with:
Hash[hash.map {|k,v| [v,k]}]
Is there a better solution?
There's a built-in method for that:
hash.invert
It's possible to invert a hash:
{ 'a' => 1, 'b' => 2 }.invert # => {1=>"a", 2=>"b"}
But be careful of the side-effects:
{ 'a' => 1, 'b' => 2, 'c' => 2 }.invert # => {1=>"a", 2=>"c"}
A hash's keys must be unique, but values don't have to be. When you invert the hash the duplicate values will collide, overwriting each other, with the last one winning.

How to get the first key and value pair from a hash table in Ruby

I'm trying to get the first key and value key from a hash table in ruby. I don't know the key values of the hash because it is passed to the method. I cant find anywhere online how to find the first key/value as a separate hash table.
I think hash[0] will just try to find an element with a name 0 it just returns nil when I run the code.
I know I can find the key name and the value and then create a new hash from them but i wonder if there is an easier way to do this so I get a hash right away.
here is my code:
def rps_game_winner(game)
rock_in_hash = game.invert['R']
paper_in_hash = game.invert['P']
scissors_in_hash = game.invert['S']
if(rock_in_hash)
if(paper_in_hash)
return paper_in_hash;
elsif(scissors_in_hash)
return rock_in_hash
end
elsif(paper_in_hash)
if(rock_in_hash)
return paper_in_hash
elsif(scissors_in_hash)
return scissors_in_hash
end
end
key = game.keys[-1]
value = game.values[-1]
winner = {key => value}
return winner
end
game_one = { "Bob" => 'P', "Jim" => 'P' }
puts rps_game_winner(game_one)
This gets me the correct result the problem is I don't understand why it's -1 instead of zero...
And i was hoping there was a better way to get the first key/value pair of a hash table instead of creating new hash table with the key and value you retrieved from the previous table.
You can just do
key, value = hash.first
or if you prefer:
key = hash.keys[0]
value = hash.values[0]
Then maybe:
new_hash = {key => value}
There is a shorter answer that does not require you to use extra variables:
h = { "a" => 100, "b" => 200 , "c" => 300, "d" => 400, "e" => 500}
Hash[*h.first] #=> {"a" => 100}
Or if you want to retrieve a key/value at a any single position
Hash[*h.to_a.at(1)] #=> {"b" => 200}
Or retrieve a key/values from a range of positions:
Hash[h.to_a[1,3]] #=> {"b"=>200, "c"=>300, "d"=>400}
[hash.first].to_h
Another way to do it.
my_hash = { "a" => "first", "b" => "second" }
{ my_hash.keys.first => my_hash.values.first }
This works too

How to get first n elements from Hash in ruby?

I have a Hash and i have sorted it using the values
#friends_comment_count.sort_by{|k,v| -v}
Now i only want to get hash of top five elements .. One way is to use a counter and break when its 5.
What is preferred way to do in ruby ?
Thanks
h = { 'a' => 10, 'b' => 20, 'c' => 30 }
# get the first two
p Hash[*h.sort_by { |k,v| -v }[0..1].flatten]
EDITED:
# get the first two (more concisely)
p Hash[h.sort_by { |k,v| -v }[0..1]]
Can't you just do something like:
h = {"test"=>"1", "test2"=>"2", "test3"=>"3"}
Then if you wanted the first 2:
p h.first(2).to_h
Result:
=> {"test"=>"1", "test2"=>"2"}
New to ruby myself (please be nice if I'm wrong guys!) but does this work?
#friends_comment_count.sort_by{|k,v| -v}.first 5
Works for me in IRB, if I've understood what you're trying to achieve correctly
You can't sort a Hash and that's why sort_by does NOT sort your Hash. It returns a sorted Array of Arrays.
In Ruby 2.2.0 and later, Enumerable#max_by takes an optional integer argument that makes it return an array instead of just one element. This means you can do:
h = { 'a' => 10, 'b' => 20, 'c' => 30 }
n = 2
p h.max_by(n, &:last).to_h # => {"b"=>20, "c"=>30}
Hashes are not ordered by nature (even thought in Ruby implementation they are). Try geting converting your Hash to Array and get [0,4] out of it

Resources