Ruby: 'case true' when does it block loop? - ruby

There is piece of code
A = "am"
F = "fm"
def fmam(n)
return if n == 0
loopy(n - 1)
case true
when n % 15 == 0
puts B + L
when n % 5 == 0
puts L
when n % 3 == 0
puts B
else
puts n
end
end
fmam(20)
in this code what does case true do it this code?

case has two forms. The form you're using compares the "target" after the case keyword ( true in this case) with each comparison (the part after each when keyword) using the === operator. You end up with a series of boolean expressions and execute the code for the first one that evaluates to true. As such, it's redundant and a bit confusing. It would be better to remove the true and use the second form of case:
case
when n % 15 == 0
puts B + L
when n % 5 == 0
puts L
when n % 3 == 0
puts B
else
puts n
end
This does the same thing but is clearer.

tutorialspoint :- says
case expression
[when expression [, expression ...] [then]
code ]...
[else
code ]
end
Compares the expression specified by case and that specified by when using the === operator and executes the code of the when clause that matches.
saying that look below:
A = "am"
F = "fm"
L = "dd"
B = 'aa'
def fmam(n)
return if n == 0
case true
when n % 15 == 0
puts B + L
when n % 5 == 0 # this evaluates to true first, which then matched with true value mentioned in the case statement.
puts L
when n % 3 == 0
puts B
else
puts n
end
end
fmam(20) #=> dd
Now look at the below code:
A = "am"
F = "fm"
L = "dd"
B = 'aa'
def fmam(n)
return if n == 0
case false
when n % 25 == 0 # this evaluates to false first, which then matched with false value mentioned in the case statement.
puts B + L
when n % 5 == 0
puts L
when n % 3 == 0
puts B
else
puts n
end
end
fmam(30) #=> aadd

You could refactor the case statement to
msg = case 0
when n % 15
B + L
when n % 5
L
when n % 3
B
else
n
end
puts msg

Related

The code below is supposed to return the least perfect square that when added to it, the sum is also a perfect square

So suppose I give 13 as n, the code should return 36 because 36 is the least perfect square that when added to 13 it gives 49 which is a perfect square. Now when I give 4 as n, it should return -1 because 4 added to all the numbers has no perfect square hence it's returning nothing. The code works without adding the elsif but that means if I pass in 4 it will return the range. But once I add the elsif it still prints out the range.
def solve n
arr = (1..10).each do |i|
i = (i**2) + n
if (Math.sqrt(i) % 1) == 0
return i - n
elsif false
return -1
end
end
arr
end
p solve(13) #= 36
# # because 36 is the smallest perfect square that can be added to 13 to form a perfect square => 13 + 36 = 49
p solve(3) #= 1 # 3 + 1 = 4, a perfect square
p solve(12) #= 4 # 12 + 4 = 16, a perfect square
p solve(9) #= 16
p solve(4) #= -1
The thing is your code is never entering to the elsif branch, that's why you're getting the (1..10) range after the iteration because that's the value arr holds and as there's no return value after checking if (Math.sqrt(i) % 1) == 0.
You could just return -1 if there was no a explicit return during the iteration:
def solve n
(1..10).each do |i|
i = (i**2) + n
return i - n if (Math.sqrt(i) % 1).zero?
end
-1
end
solve(3) # 1
solve(12) # 4
solve(9) # 16
solve(4) # -1

How to multiply integer digits between them?

I want to my n to multiply with next number for example if n=99 i want it to 9*9 and then return a result, and then i want the result (9*9 = 81 then 8*1 = 8) to multiply until it becomes 1 digit.
Here's my code:
def persistence(n)
if n <= 9
puts n
else
n.to_s.each_char do |a|
a.to_i * a.to_i unless n < 9
puts a.to_i
end
end
end
and i want it to return this:
persistence(39) # returns 3, because 3*9=27, 2*7=14, 1*4=4
# and 4 has only one digit
persistence(999) # returns 4, because 9*9*9=729, 7*2*9=126,
# 1*2*6=12, and finally 1*2=2
persistence(4) # returns 0, because 4 is already a one-digit number
def persistence(n)
i = 0
while n.to_s.length != 1
n = n.to_s.each_char.map(&:to_i).reduce(:*)
i +=1
end
i
end
persistence(39) #=> 3
persistence(999) #=> 4
Other version:
def p(n, acc)
return acc if n <= 9
p(n.to_s.each_char.map(&:to_i).reduce(:*), acc+1)
end
def persistence(n)
p(n, 0)
end
I will leave the breaking down of method and understanding what's happening and what is the difference b/w two variations to you. Will love to see your comment explaining it.
def persistence(n)
0.step.each do |i|
break i if n < 10
n = n.digits.reduce(:*)
end
end
persistence 4 #=> 0
persistence 39 #=> 3
persistence 999 #=> 4
persistence 123456789123456789 #=> 2
Regarding the last result, note that 2*5*2*5 #=> 100.

Is it better way to do that?

I wrote a simple script to sum all digits of positive integer input until 1 digit is left ( for example for input 12345 result is 6 because 1+2+3+4+5 = 15 and 1+5 = 6). It works but is it better way to do that? ( more correct?)
here is a code:
def sum(n)
string=n.to_s
while string.length > 1 do
result=string.chars.inject { |sum,n| sum = sum.to_i + n.to_i}
string=result.to_s
end
puts "Sum of digits is " + string
end
begin
p "please enter a positive integer number:"
number = Integer(gets.chomp)
while number<0
p "Number must be positive!Enter again:"
number = Integer(gets.chomp)
end
rescue
p "You didnt enter integer!:"
retry
end
sum(number)
According to Wikipedia, the formula is:
dr(n) = 1 + ((n − 1) mod 9)
So it boils down to:
def sum(n)
1 + (n - 1) % 9
end
To account for 0, you can add return 0 if n.zero?
You could use divmod (quotient and modulus) to calculate the digit sum without converting to / from string. Something like this should work:
def sum(number)
result = 0
while number > 0 do
number, digit = number.divmod(10)
result += digit
if number == 0 && result >= 10
number = result
result = 0
end
end
result
end
sum(12345) #=> 6
The line
number, digit = number.divmod(10)
basically strips off the last digit:
12345.divmod(10) #=> [1234, 5]
1234 becomes the new number and 5 is being added to result. If number eventually becomes zero and result is equal or greater than 10 (i.e. more than one digit), result becomes the new number (e.g. 15) and the loops starts over. If result is below 10 (i.e. one digit), the loop exits and result is returned.
Short recursive version:
def sum_of_digits(digits)
sum = digits.chars.map(&:to_i).reduce(&:+).to_s
sum.size > 1 ? sum_of_digits(sum) : sum
end
p sum_of_digits('12345') #=> "6"
Single call version:
def sum_of_digits(digits)
digits = digits.chars.map(&:to_i).reduce(&:+).to_s until digits.size == 1
return digits
end
It's looking good to me. You might do things a little more conscise like use map to turn every char into an integer.
def sum(n)
string=n.to_s
while string.length > 1 do
result = string.chars.map(&:to_i).inject(&:+)
string = result.to_s
end
puts "Sum of digits is " + string
end
You could also use .digits, so you don't have to convert the input into a string.
def digital_root(n)
while n.digits.count > 1
array = n.digits
n = array.sum
end
return n
end

Ruby - Sum Results of Select()

I'm doing www.eulerproject.net, the first problem:
If we list all the natural numbers below 10, that are multiples of 3
or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. Find
the sum of all the multiples of 3 or 5 below 1000.
The following is the code I have so far.
(3..999).to_a.select do |x|
x % 3.0 == 0 || x % 5.0 == 0
end
It would be easy to append the numbers into an array, but how can this be done by how can this be done by chaining a method onto the end of this. Something like
p start loop
do stuff
end.sum
To answer the question - yes, you can chain the method like you've shown.
(3..999).to_a.select do |x|
x % 3 == 0 || x % 5 == 0 # you don't have to use floats here, integers would work
end.inject(:+)
#=> 233168
The rule of a style guides is to NOT to chain methods to multiline do end blocks, but it is a working code.
It's the same as writing
(3..999).to_a.select { |x| x % 3 == 0 || x % 5 == 0 }.inject(:+)
#=>233168
Array#sum is an ActiveSupport method, not Ruby's, but I think you should use Ruby's methods in eulerproject tasks.
You are summing arithmetic series, so there is no need to iterate:
def sum(n,m)
p = n/m
m*p*(1+p)/2
end
n = 999
sum(n,3) + sum(n,5) - sum(n,15)
#=> 233168
Consider:
n = 100
m = 3
p = 100/3 #=> 33
sum(100,3) = 3 + 6 + 9 +...+ 99
= 3 * (1 + 2 +...+ p)
= 3 * p(1+p)/2
We need to subtract sum(100,15) because sum(100,3) + sum(100,5) double-counts:
sum(100,15) = 15 + 30 + 45 + 60 + 75 + 90
if you want to get the sum of array, you can do like this:
(3..999).inject(0) { |sum, e| e % 3 == 0 || e % 5 == 0 ? sum += e : sum }
=> 233168
it just need once loop.
You can omit the to_a, since calling 'select' to (3..999) will still return an array regardless.
Andrey's answer is the most compact one with :
(3..999).select{ |x| x % 3 == 0 || x % 5 == 0 }.inject(:+)

Problems with Modulo operator Ruby: Why am I getting "undefined method `%' for 1..100:Range"?

For some reason I'm getting the error undefined method '%' for 1..100:Range when I run the following code:
[1..100].each do |x|
if x % 3 == 0 && x % 5 == 0
puts "CracklePop"
elsif x % 3 == 0
puts "Crackle"
elsif x % 5 == 0
puts "Pop"
else
puts x
end
end
Any idea what's going on? Any help is much appreciated.
That's the wrong syntax for ranges.
You've made an array with 1 element, and that element is itself the range 1..100. What you've written is equivalent to [(1.100)]. You're iterating over the outer array one time, and setting x to (1..100)
You want (1..100).each, which invokes each on the range, not on an array containing the range.
By doing [1..100] you are not looping from 1 to 100 but on 1..100, which is a Range object, what you really want to do is:-
(1..100).step do |x|
if x % 3 == 0 && x % 5 == 0
puts "CracklePop"
elsif x % 3 == 0
puts "Crackle"
elsif x % 5 == 0
puts "Pop"
else
puts x
end
end
Basically, Range represents an interval, you can iterate over Range as explained here, create an array from Range as explained here and more details on range can be found here.
Just as it says. 1..100 does not have a method %. The expression (1..100) % 3 is undefined.

Resources