Append the count to a variable name in ruby - ruby

I have the following code:
count = 0
3.times do |survey|
count = count + 1
#psychological_safety_score_ + count.to_s = Team.get_psychological_safety_score(#team, count)
end
This gives me the error undefined method to_s= for 1:Integer
I'm also tried #psychological_safety_score_ + #{count.to_S} with no luck.
The end goal is to get instance variables of psychological_safety_score_1...3

The Ruby language itself does not allow you to compute variable names by interpolating data into them.
It is still possible to do what you want though, using instance_variable_set.
score = Team.get_psychological_safety_score(#team, count)
variable = :"#psychological_safety_score_#{count}"
instance_variable_set variable, score
Also, count is redundant. Integer#times iterates self times, yielding the current index to the block. It can be used as the count.

Related

How to solve fibonacci in ruby (HackerRank)

I am trying to solve a Fibonacci solution in HackerRanck.
I am mostly using the inject method.
I first declared an empty array.
I then define a method that takes in a parameter and turns it into a list that stores two initial values, 0 and 1.
The method then takes the last two values and sum them up together and returns the newly-formed list. (I hope I got this logic right)
I was then aiming at calling the method and loop through it this time around summing all the even values in it and returning the final result.
#!/bin/ruby
t = gets.strip.to_i
for a0 in (0..t-1)
n = gets.strip.to_i
end
result = 0
def fibbonacci num
(1..num).inject([0, 1]) { |fib| << fib.last(2).inject(:+)}
end
my_fib_num = fibbonacci n
for i in my_fib_num
if i % 2 == 0
result.inject(0){|sum,x| sum + x }
end
end```
Anything I could be getting wrong here?
I see you are doing unnecessary things over here and you are using inject in completely wrong way. The inject should always be called on an array or a range object. On every loop the result of the loop will be assigned to first parameter (i.e result in the example below) of the block and it will be passed back again to next loop. Finally returns the value in result.
The updated code:
#!/bin/ruby
t = gets.strip.to_i
def fibbonacci(num)
(1..num).inject([0, 1]) { |result| result << result.last(2).inject(:+)}
end
my_fib_num = fibbonacci(t)
result = my_fib_num.inject(:+)
Note: The solution is to solve by using inject.
Ref: https://apidock.com/ruby/Enumerable/inject
May be you can use select and inject together to some the even
t = gets.strip.to_i
def fibbonacci(num)
(1..num).inject([0, 1]) { |fib| fib << fib.last(2).inject(:+)}
end
my_fib_num = fibbonacci(t)
my_fib_num.keep_if{|d| d.even?}.inject(:+)

Why Ruby doesn't allow setting a local variable using an expression containing a field reader with the same name as the local variable?

Consider the following code.
class A
attr_reader :n
def initialize
#n = 1
end
def set_local_n
n = 10
end
def using_field_reader_locally
n + 100
end
def using_field_reader_to_set_local_x
x = n + 1000
end
def using_field_reader_to_set_local_n
n = n + 1000 # This line raises a NoMethodError. Why?
end
end
Why would the commented line produce an error? Why Ruby doesn't allow setting a local variable, n in this case, using an expression containing a field reader with the same name as the local variable? Why would all other instance methods run without any problem but using_field_reader_to_set_local_n produce an error.
Please note that I am NOT intending to define n locally in using_field_reader_to_set_local_n with an expression involving the locally defined n in set_local_n. I am intending to define n locally in using_field_reader_to_set_local_n with an expressing involving the field reader of #n. The definition of set_local_n is for showing that n can be defined locally while a field reader named n exists.
If you look closely, the NoMethodError isn't about there being no method n, but method + for NilClass.
In this statement:
n = n + 1000
Ruby has to decide what n is. As you are assigning something to it (n =) it's not a method. If you wanted to call the n= method, you had to specify an explicit receiver (self.n =).
So it has to be a variable. In this case local variable.
Now to make sense of something like:
n = n
Ruby ends up assigning nil to n. This has to do with the internals having to put a placeholder for a variable name that is being assigned.
So when you do:
n = n + 1000
What happens is:
Create a new local variable n with placeholder value (nil).
Attempt to assign to it whatever is on the right.
Calculate what is on the right - nil + 1000.
nil doesn't have a + method so an error is raised.
To do what you wanted to do, you have to explicitly reference the instance variable for its value:
n = #n + 1000
Or explicitly call the attribute reader:
n = self.n + 1000

Global vs local variables?

I am wondering why my code works in one instance but doesn't in another. Does it have something to do with local and global variables?
This works:
def factorial num
result = 1
while (num > 1)
result = result * num
num -= 1
end
puts result
end
This doesn't work:
result = 1
def factorial num
while (num > 1)
result = result.to_i * num
num -= 1
end
puts result
end
Everything inside of a method definition cannot see local variables from other places. That sounds weird, but here's two ways to fix it:
result = 1
number = 10
def factorial(num,result_value)
while (num > 1)
result_value = result_value.to_i * num
num -= 1
end
puts result_value
end
factorial(number, result)
That passes result as an argument. That's a great way of handling the method because it doesn't allow you to change the value of result from within the method. That might not seem like a big deal but "pure methods" like this become very valuable as the size the code increases.
This is the "dirty" or un-pure way of doing the same thing:
#result = 1
def factorial(num)
while (num > 1)
#result = #result.to_i * num
num -= 1
end
puts #result
end
Putting an # in front of a variable name allows its scope to expand to methods defined outside of its scope. This becomes a problem as the complexity of your code increases.
Random personal opinion: even though Ruby doesn't require you to put the parentheses next to a method definition, you always should. It makes the code a lot more explicit and easier to read. Follow your heart though ;)
You could experiment by prepending all results with a $ sign, making it global. Prepending with a # results in an instance variable, also interesting. Sidenote: puts prints and returns nil, so your method returns nil.
result = 1 # line 1
def factorial num
while (num > 1)
result = result.to_i * num
num -= 1
end
puts result
end
In this code, factorial doesn't know about result variable from the line 1.
When Ruby find result = result.to_i * num in your method it will first assign nil to the result. Then Ruby will try to run result.to_i * num. Since result is already nil, result.to_i is equal 0.
Here is another example:
def foo
a = a
puts "#{a.class}"
end
foo #NilClass
In the Doesn't Work version the result variable you've assigned to 1 isn't visible inside the factorial method.
Now there is a possibly unexpected behaviour in Ruby that if you try to assign a variable and you refer to the same variable on the right hand side of the assignment, if that variable doesn't have a value yet then it is treated as nil rather than raising an error. So the first time round the loop when you perform
result = result.to_i * num
it's equivalent to result = nil.to_i * num and nil.to_i is equal to 0 so this then sets up result to be 0 for subsequent iterations of the loop and as you're just multiplying the value of result stays on 0.

Ruby inject method

I'm doing some ruby exercises. In one of the solutions of my exercise, I found this code.
def make_change(amount)
{ H:50, Q:25, D:10, N:5, P:1 }.inject({}) do |res, (k,v)|
change, amount = amount.divmod(v)
res[k] = change unless change==0
res
end
end
This method takes an amount as parameter and associates coins to equal it. For example:
make_change(75)
#=> {H:1, Q:1}
(50 + 25 = 75)
But I don't understand where the change variable come from. How is the variable filled?
But i doesnt understand where does the "change" variable come from, how the variable is filled ?
change is defined and initialized in the first line of the block:
change, amount = amount.divmod(v)

In Ruby, how can I collect each new element passing through a method into an array?

I'm creating a small prime number program, and am confused about one thing.
I have a function called create_numbers, that generates numbers and passes them to a new function called check_for_primes, which passes only prime numbers to a final function called count_primes. I want to collect each prime into an array in the function count_primes, but for some reason each number is collected as its own array.
Any idea of what I'm doing wrong?
Here is the code:
def create_numbers
nums = 1
while nums < 100
nums = nums + 2
check_for_primes(nums)
end
end
def count_primes(nums)
array = []
array << nums
puts array.inspect
end
def check_for_primes(nums)
(2...nums).each do |i|
if nums%i == 0
nums = false
break
end
end
if nums != false
count_primes(nums)
end
end
create_numbers
Try this:
START = 1
STEP = 2
class Integer
def prime?
return if self < 2
(2...self).each do |i|
return if self % i == 0
end
true
end
end
def create_numbers
num = START
while (num + STEP) < 100
num += STEP
primes << num if num.prime?
end
end
def primes
#primes ||= []
end
create_numbers
p primes
When you want to save the 'state' of something, put it in an instance variable (#var).
It'll be accessible outside of the current function's scope.
Also, try naming your variables differently. For instance, instead of 'nums', in the
create_numbers method, use 'num'. Since the variable is only referencing one number at a
time and not a list of numbers, naming it in the plural will confuse people (me included)...
Hope it helps,
-Luke
each time into count_primes you put a value into array (which should have a better name, btw). Unfortunately, each time it's a new variable called array and since no one outside the function can see that variable it's lost when the function ends. If you want to save the values you've already found you'll need to set some state outside your function.
I can think of 2 quick solutions. One would be to declare your storage at the top of create_numbers and pass it into both functions.
def count_primes(num, arr)
def check_for_primes(nums, arr)
The other would be to set a variable outside all the functions, $array, for example to hold the values.
$array = []
...
$array << num
Since the scope of $array is global (i.e. all functions have access to it) you have access to it from anywhere in the file and can just add things to it in count primes. Note that using globals in this way is generally considered bad style and a more elegant solution would pass parameters and use return values.

Resources