Counters inside a function - ruby

I'm trying to get a some counters inside a function that gets called repeatly.
In the function, gets is passed a value between 1 and 6 and then inside the function are a bunch of if statements. Inside the if statements I want to put a counter so I know how times each part of the if statement is true.
I've tried x = x+1 inside the if but it doesn't like that:
def check(number)
if number == 1
x = x+1
if x == 3
return true
end
elsif number == 2
y = y+1
elsif number == 3
z = z + 1
end
end
Any suggestions?

The pattern you're using here is a clunky way of doing this:
def check(number)
case (number)
when 1
#x += 1
true
when 2
#y += 1
when 3
#z += 1
end
end
Remember that in Ruby the last statement to evaluate is the one that's returned by default, so there's no need to be explicit about the return unless there's additional code after that point. In this case there isn't.
Secondly, unless you have attr_accessors, then x = x + 1 isn't going to do anything useful. That will declare a local, initially nil, and then try and add 1 to it, an invalid operation. Presumably you mean to have #x initialized to 0 elsewhere and then track it in here.

Local variables don't retain their values across different invocations of a method, that would be very weird.
If the counter values are semantically a property of the method itself, I would use a closure:
x = y = z = 0
define_method(:check) do |number|
case number
when 1 then x += 1; return true if x == 3
when 2 then y += 1
when 3 then z += 1
end
end
Alternatively, if the counter values are semantically a property of the object, I would use private getters and setters:
def check(number)
case number
when 1 then self.x += 1; return true if x == 3
when 2 then self.y += 1
when 3 then self.z += 1
end
end
private
attr_accessor :x, :y, :z
def initialize
self.x = self.y = self.z = 0
end

Related

Ruby undefined Method/NoMethodError '*' for nil:NilClass, works until looped

My program orders arrays 1 and 2, and iterates to check whether each element in 1 is the sqrt of each element in 2. I've tested the comparison without the loop and it works fine, so I don't think that there's an uninitialised variable.
def comp(array1, array2)
order1 = array1.sort
order2 = array2.sort
i = 0
while i < order1.length
if order1[i] * order1[i] == order2[i]
i += 1
else
false
end
end
order1[i] * order1[i] == order2[i]
end
Can you point me in the direction of the issue? I've also not used Math.sqrt because it times out on my interface.
Your i equals order1.length, after your loop, so the last line of your method is basically
order1[order1.length] * order1[order1.length] == order2[order1.length]
which is (assuming your arrays are the same length):
nil * nil == nil
which throws an error. Not sure why you need the last line, if you remove it and simply return a counter, your method works as expected if you use a dedicated counter, for the elements which match your condition, instead of using index for that (your index has to be incremented always):
def comp(array1, array2)
order1 = array1.sort
order2 = array2.sort
i = 0
counter = 0
while i < order1.length
if order1[i] * order1[i] == order2[i]
counter += 1
end
i += 1
end
counter
end
In Ruby it is pretty common to use proper enumerators for iterating over collections, so your while can be nicely substituted by Enumerable#each_with_index:
def comp(array1, array2)
order1 = array1.sort
order2 = array2.sort
counter = 0
order1.each_with_index do |el, i|
if el * el == order2[i]
counter += 1
end
end
counter
end
And as the last step, we can also Array#count how many elements in an array meet a certain condition without needing to specify a local variable, like so:
def comp(array1, array2)
order2 = array2.sort
array1.sort.each_with_index.count { |el, i| el ** 2 == order2[i] }
end

What is the correct way to write this in Ruby?

I am needing to write few methods: value(x), zero(a,b,e), area(a,b), derivative(x)
class Funkcja
def initialize(funkcja)
#funkcja = funkcja
end
def value(x)
#funkcja.call(x)
end
end
This class will have to work over block which is an object from Proc
This is how I create that new object
f = Funkcja.new (Proc.new{|x| x*x*Math.sin(x)})
What is the correct way and in Ruby style (if not please show me that i
newbie in Ruby) to do this right Funkcja.new (Proc.new x) and
initialize #funkcja = funkcja
def zero(a, b, eps)
x = (a+b)/2.0
val = value(x)
if val >= -eps and val <= eps
x
else
left = value(a)
rigth = value(b)
if left < 0 and val > 0
zero(a,x,eps)
elsif left > 0 and val < 0
zero(a,x,eps)
elsif rigth > 0 and val < 0
zero(x,b,eps)
elsif rigth < 0 and val > 0
zero(x,b,eps)
elsif value == 0
x
else
nil
end
end
end
def area(a,b)
pole = 0
while a < b
if (self.value(a) > self.value( a + 0.00001))
pole = pole + (self.value( a) * 0.00001)
else
pole = pole + (self.value( a + 0.00001) * 0.00001 )
end
a += 0.00001
end
pole
end
def derivative(x)
eps = 0.00000001
return (self.value(x) - self.value(x - eps))/eps
end
Area is calculated area between a and b and OX, zero is find where
F (x)=0 derivative is calculated as derivative in point.
The main thing that's non-idiomatic is this:
f = Funkcja.new (Proc.new{|x| x*x*Math.sin(x)})
What would be more normal is to do this:
f = Funkcja.new { |x| x*x*Math.sin(x) }
This is a normal block, and you could split it up among multiple lines as usual:
f = Funkcja.new do |x|
x*x*Math.sin(x)
end
However, this wouldn't work with your initialize definition and that's because of one minor detail. You'd just need to change def initialize(funkcja) to def initialize(&funkja) - this converts the passed block into a proc that you can assign to a variable, use call with, etc:
def initialize(&funjka)
#funkja = funkja
end
Another way to do the same thing would be this:
def initialize
#funkja = yield
end
Other than that, your code seems fine with one other glaring non-idiomatic thing, which that you use self.value. The self is unnecessary unless you're using a setter method (i.e. self.value =), which you're not here.
Here's an idea of adapting one of your methods to a more Ruby style:
def area(a,b)
pole = 0
while a < b
if (yield(a) > yield(a + 0.00001))
pole = pole + (yield(a) * 0.00001)
else
pole = pole + (yield(a + 0.00001) * 0.00001)
end
a += 0.00001
end
pole
end
You'd use it like this:
area(a, b) do |a|
a ** 2
end
Now it's one thing to be handling Proc objects, that's fine, the do ... end method of appending blocks to method calls generates those by default. It's very not Ruby to put extra methods on Proc itself. I can't see anything here that can't be covered by defining these inside a simple module:
module CalculationModule
def area(a, b)
# ... Implementation
end
extend self
end
That way you can use those methods like CalculationModule.area or you can always include it into another class or module and use them like area.

NoMethodError with .chr.to_i

I'm trying to create a recursive method sum_of_digits(i) that takes the sum of integers, i.e. '456' = 4+5+6 = 15
However, I receive a NoMethodError for chr.to_i in the following code:
def sum_of_digits(i)
input = i.to_s
if i == 0
return 0
elsif input.length == 1
return i
else
for n in 1..input.length
sum += input[i].chr.to_i % 10^(n-1)
end
end
return sum
end
Thank you!
String indexes are zero-based in ruby. The problem is here:
for n in 1..input.length
it should be written as
for n in 0..input.length-1
BTW, call to chr is superfluous as well, since you already have a string representation of a digit there. As well, sum must be declared in advance and set to zero.
Also, the whole code is not ruby idiomatic: one should avoid using unnecessary returns and for-loop. The modified version (just in case) would be:
def sum_of_digits(i)
input = i.to_s
case
when i == 0 then 0 # return zero
when input.length == 1 then i # return i
else
sum = 0
input.length.times do |index|
sum += input[index].to_i % 10^index
end
sum
end
end
or, even better, instead of
sum = 0
input.length.times do |index|
sum += input[index].to_i % 10^index
end
sum
one might use inject:
input.length.times.inject(0) do |sum, index|
sum += input[index].to_i % 10^index
end

Why doesn't my conversion code for roman numbers ('mcmxcix' for e.g) to real numbers work?

I want to convert Roman numerals, such as "mcmxcix", to arabic integers like "1999".
My code looks like:
#~ I = 1 V = 5 X = 10 L = 50
#~ C = 100 D = 500 M = 1000
def roman_to_integer roman
len = roman.length
x = 1
while x <= len
arr = Array.new
arr.push roman[x]
x += 1
end
num = 0
arr.each do |i|
if i == 'I'
num += 1
elsif i == 'V'
num += 5
elsif i == 'X'
num += 10
elsif i == 'L'
num += 50
elsif i == 'C'
num += 100
elsif i == 'D'
num += 500
elsif i == 'M'
num += 1000
end
end
num
end
puts(roman_to_integer('MCMXCIX'))
The output is 0, but I don't understand why?
Ruby doesn't have a post-increment operator. When it sees ++ it interprets that as one infix + followed by one prefix (unary) +. Since it expects an operand to follow after that, but instead finds the keyword end, you get a syntax error.
You need to replace x++ with x += 1.
Furthermore note that x isn't actually in scope inside the roman_to_integer method (which isn't a syntax error, but nevertheless wrong).
Additionally you'll have to replace all your ifs except the first with elsifs. The way you wrote it all the ifs are nested, which means that a) you don't have enough ends and b) the code doesn't have the semantics you want.
You are missing a closing parentheses so
puts(roman_to_integer('mcmxcix')
should be
puts roman_to_integer('mcmxcix')
or
puts(roman_to_integer('mcmxcix'))
The arr keeps getting annihilated in your while loop, and it is not in the scope outside of the loop. Move the following line above the while statement:
arr = Array.new

more ruby way of doing project euler #2

I'm trying to learn Ruby, and am going through some of the Project Euler problems. I solved problem number two as such:
def fib(n)
return n if n < 2
vals = [0, 1]
n.times do
vals.push(vals[-1]+vals[-2])
end
return vals.last
end
i = 1
s = 0
while((v = fib(i)) < 4_000_000)
s+=v if v%2==0
i+=1
end
puts s
While that works, it seems not very ruby-ish—I couldn't come up with any good purely Ruby answer like I could with the first one ( puts (0..999).inject{ |sum, n| n%3==0||n%5==0 ? sum : sum+n }).
For a nice solution, why don't you create a Fibonacci number generator, like Prime or the Triangular example I gave here.
From this, you can use the nice Enumerable methods to handle the problem. You might want to wonder if there is any pattern to the even Fibonacci numbers too.
Edit your question to post your solution...
Note: there are more efficient ways than enumerating them, but they require more math, won't be as clear as this and would only shine if the 4 million was much higher.
As demas' has posted a solution, here's a cleaned up version:
class Fibo
class << self
include Enumerable
def each
return to_enum unless block_given?
a = 0; b = 1
loop do
a, b = b, a + b
yield a
end
end
end
end
puts Fibo.take_while { |i| i < 4000000 }.
select(&:even?).
inject(:+)
My version based on Marc-André Lafortune's answer:
class Some
#a = 1
#b = 2
class << self
include Enumerable
def each
1.upto(Float::INFINITY) do |i|
#a, #b = #b, #a + #b
yield #b
end
end
end
end
puts Some.take_while { |i| i < 4000000 }.select { |n| n%2 ==0 }
.inject(0) { |sum, item| sum + item } + 2
def fib
first, second, sum = 1,2,0
while second < 4000000
sum += second if second.even?
first, second = second, first + second
end
puts sum
end
You don't need return vals.last. You can just do vals.last, because Ruby will return the last expression (I think that's the correct term) by default.
fibs = [0,1]
begin
fibs.push(fibs[-1]+fibs[-2])
end while not fibs[-1]+fibs[-2]>4000000
puts fibs.inject{ |sum, n| n%2==0 ? sum+n : sum }
Here's what I got. I really don't see a need to wrap this in a class. You could in a larger program surely, but in a single small script I find that to just create additional instructions for the interpreter. You could select even, instead of rejecting odd but its pretty much the same thing.
fib = Enumerator.new do |y|
a = b = 1
loop do
y << a
a, b = b, a + b
end
end
puts fib.take_while{|i| i < 4000000}
.reject{|x| x.odd?}
.inject(:+)
That's my approach. I know it can be less lines of code, but maybe you can take something from it.
class Fib
def first
#p0 = 0
#p1 = 1
1
end
def next
r =
if #p1 == 1
2
else
#p0 + #p1
end
#p0 = #p1
#p1 = r
r
end
end
c = Fib.new
f = c.first
r = 0
while (f=c.next) < 4_000_000
r += f if f%2==0
end
puts r
I am new to Ruby, but here is the answer I came up with.
x=1
y=2
array = [1,2]
dar = []
begin
z = x + y
if z % 2 == 0
a = z
dar << a
end
x = y
y = z
array << z
end while z < 4000000
dar.inject {:+}
puts "#{dar.sum}"
def fib_nums(num)
array = [1, 2]
sum = 0
until array[-2] > num
array.push(array[-1] + array[-2])
end
array.each{|x| sum += x if x.even?}
sum
end

Resources