Dynamic variable names in Ruby - ruby

#baseball_games = 0
#basketball_games = 0
#football_games = 0
Game.all.each do |game|
instance_variable_set("##{game.sport.name.downcase}_games", instance_variable_get("##{game.sport.name.downcase}_games") + 1)
end
Is there a better way to do this, than calling the get method inside the set method? I really am just trying to += the dynamic variable...

Building upon #Santosh's answer, you could do this more generally:
#games = Sport.all.map { |sport| [sport.name.to_sym, sport.games.count] }.to_h

Another solution, without the loop (Assuming the relation is sport has_many games)
#games = {
:baseball => Sport.find_by_name('baseball').games.count,
:basketball => Sport.find_by_name('basketball').games.count,
:football => Sport.find_by_name('football').games.count
}

#games = {:baseball => 0, :basketball => 0, :football => 0 }
Game.all.each do |game|
#games[game.sport.name.downcase.to_sym] = #games[game.sport.name.downcase.to_sym] + 1
end

Related

adding a hash to hash or symbol on the fly Ruby

I would like to know how to add a hash to hash on the fly
and increment the hashes on the inside.
words_to_scan.scan(/\w+|\?|\.|!|\,/).select do |aword|
if words_from_file.has_key?(aword.to_sym)
words_from_file[aword.to_sym]['pop'] += 1
else
words_from_file[aword.to_sym]['pop'] = 1
end
end
i am trying to create something like
words_from_file = {:the => {'pop' => 3, 'positions' => [1,6,10]}}
words_from_file = {}
words_to_scan.scan(/\w+|\?|\.|!|\,/).select do |aword|
words_from_file[aword.to_sym] ||= {} # declare hash if was not already declared
words_from_file[aword.to_sym]['pop'] ||= 0 # set pop if was not already set
words_from_file[aword.to_sym]['pop'] += 1 # increment
end
The default_proc of a Hash runs whenever a key is not found. Here it creates a new Hash as value for the new key:
words_from_file.default_proc = Proc.new{|h,k,v| h[k] = {'pop' => 0, 'positions' => []} }
words_to_scan.scan(/\w+|\?|\.|!|\,/).each do |aword|
words_from_file[aword.to_sym]['pop'] += 1
end

Ruby function as value of hash

I was wondering if or how it is possible to map a function to a value of a hash.
For example:
----Start Class------------
def foo(var)
return var + 2
end
hash_var = { func => foo() }
----End Class--------------
so that I could later call
Class::hash_var["func"][10]
or
Class::hash_var["func"](10)
and that would return 12?
You could use method method.
def foo(var)
return var + 2
end
hash_var = { :func => method(:foo) }
hash_var[:func].call(10)
Functions/methods are one of the few things in Ruby that are not objects, so you can't use them as keys or values in hashes. The closest thing to a function that is an object would be a proc. So you are best off using these...
The other answers pretty much listed all possible ways of how to put a proc into a hash as value, but I'll summarize it nonetheless ;)
hash = {}
hash['variant1'] = Proc.new {|var| var + 2}
hash['variant2'] = proc {|var| var + 2}
hash['variant3'] = lambda {|var| var + 2}
def func(var)
var + 2
end
hash['variant4'] = method(:func) # the *method* method returns a proc
# describing the method's body
there are also different ways to evaluate procs:
hash['variant1'].call(2) # => 4
hash['variant1'][2] # => 4
hash['variant1'].(2) # => 4
You can set the value to a Proc and call it.
hash_var = {
'func' => proc {|x| x+2}
}
hash_var['func'].call(10) #=> 12
Try using lambdas
hash_var = { :func => lambda { |var| var + 2 }}
hash_var['func'].call(5) #=> 7
Another option would be:
def foo(name)
puts "Hi #{name}"
end
def bar(numb)
puts numb + 1
end
hash_var = { func: :foo, func2: :bar }
send hash_var[:func], "Grid"
# => Hi Grid
send hash_bar[:func2], 3
# => 4
Here is some information about the #send method What does send() do in Ruby?

Ruby - Convert Array with pipe delimited values to an array of hashes

How do I make this:
["ford|white", "honda|blue"]
Into this:
[{'make'=>'ford', 'color'=>'white'}, {'make'=>'honda', 'color'=>'blue'}]
["ford|white", "honda|blue"].collect do |str|
ary = str.split('|')
{ 'make' => ary[0], 'color' => ary[1] }
end
gives me
[{"color"=>"white", "make"=>"ford"}, {"color"=>"blue", "make"=>"honda"}]
Without thought:
> l = ["ford|white", "honda|blue"]
> m = l.collect { |m| make, color = m.split('|'); { make: make, color: color } }
=> [{:make=>"ford", :color=>"white"}, {:make=>"honda", :color=>"blue"}]
(Using symbols for keys, generally recommended, IMO.)
input = ["ford|white", "honda|blue"]
input.map do |car|
Hash[ %w(make color).zip car.split('|') ]
end
=> [{"make"=>"ford", "color"=>"white"}, {"make"=>"honda", "color"=>"blue"}]
This should do it
yourarray = ["ford|white", "honda|blue"]
yourhash = yourarray.map­ {|x| y = x.spl­it('|'); {"mak­e" => y[0],­ "colo­r" => y[1]}­}

Ruby, using interpolation in variables' names

If I have variables as below,
i = 1
k1 = 20
is there any ways to get values of k1 with the interpolation of i?
Something like,
k"#{i}"
=> 20
Thanks in advance.
It depends on whether it's a local variable or a method. send "k#{i}" should do the trick with methods:
class Foo
attr_accessor :i, :k1
def get
send "k#{i}"
end
end
foo = Foo.new
foo.i = 1
foo.k1 = "one"
foo.get
# => "one"
If you really need to, you can access local variables using the current Binding and local_variable_get:
i = 1
k1 = "one"
local_variables
# => [:i, :k1]
binding.local_variable_get("k#{i}")
# => "one"
This is pretty awful though. In this instance you'd be better off using a Hash:
i = 1
k = {1 => "one"}
k[i]
# => "one"

Ruby: Hash assignment with concurrent loops

Say I have an array:
array = [6, 6, 6, 4, 4, 6, 4, 4]
and I have another array of strings:
quadrant = ["upper_left", "upper_right", "lower_left", "lower_right"]
and I have a 8 x 8 2-d array consisting of board locations(#board) that are either nil or Checker objects.
My goal is to create a hash such:
hash = { "upper_left" => #board[array[0]][array[1]] ,
"upper_right" => #board[array[2]][array[3]] ,
"lower_left" => #board[array[4]][array[5]] ,
"lower_left" => #board[array[6]][array[7]] }
I have the following code:
jump_positions = {}
QUADRANTS.each do |quad|
array.each_slice(2) do |coord|
jump_positions[quad] = #board[coord[0]][coord[1]]
end
And then the test:
it "should assign board locations as adjacent positions and deliver that info as a whole" do
#bs.board = board.create_board
x_coord = 3
y_coord = 1
jump_assignments = #bs.assign_adjacent_positions(x_coord, y_coord)
jump_assignments["upper_left"].class.should == nil
jump_assignments["upper_right"].class.should == nil
jump_assignments["lower_left"].class.should == Checker
jump_assignments["lower_right"].class.should == Checker
end
fails because all the assignments are of class 'Checker' and turns out they're all the same 'Checker' object. I know its doing this because the loops are nested so all the 'quad' keys are getting initialize to the last board location.
Is there a way I can assign the value to the key with a value from the 'array' in one pass so that they get assigned correctly? Does this question even make sense?
I think you just need to add a little map to my answer to your other similar question:
hash = Hash[quadrant.zip(array.each_slice(2).map { |a| #board[a.first][a.last] })]
Given a board like this:
#board = [
['11', '12', ... '18'],
['21', '22', ... '28'],
...
['81', '82', ... '88']
]
the above construct gives me a hash like this:
{
"upper_left" => "77",
"upper_right" => "75",
"lower_left" => "57",
"lower_right" => "55"
}
and that seems to be what you're looking for.
mu too short made me reconsider my question, and I believe my algorithm was broken. I actually ended up breaking this method down into three interdependent methods:
def deltas_to_board_locations(deltas, x, y)
board_coords = []
deltas.each_slice(2) do |slice|
board_coords << x + slice[0]
board_coords << y + slice[1]
end
board_coords
end
def assign_adjacent_board_coords(x, y)
jump_positions = Hash[QUADRANTS.zip(deltas_to_board_locations(normal_deltas, x, y).each_slice(2))]
end
def determine_adjacent_positions_content(board, board_coords)
adjacent_content = {}
board_coords.each_pair { |quad, coords| adjacent_content[quad] = board[coords[0]][coords[1]] }
adjacent_content
end
which worked out quite nicely.

Resources