How could I DRY this while loop? - ruby

I need to DRY this code but I don't know how.
I tried to dry the if condition but I don't know how to put the while in this.
def sum_with_while(min, max)
# CONSTRAINT: you should use a while..end structure
array = (min..max).to_a
sum = 0
count = 0
if min > max
return -1
else
while count < array.length
sum += array[count]
count += 1
end
end
return sum
end

Welcome to stack overflow!
Firstly, I should point out that "DRY" stands for "Don't Repeat Yourself". Since there's no repetition here, that's not really the problem with this code.
The biggest issue here is it's unrubyish. The ruby community has certain things it approves of, and certain things it avoids. That said, while loops are themselves considered bad ruby, so if you've been told to write it with a while loop, I'm guessing you're trying to get us to do your homework for you.
So I'm going to give you a couple of things to do a web search for that will help start you off:
ruby guard clauses - this will reduce your if-else-end into a simple if
ruby array pop - you can do while item = array.pop - since pop returns nil once the array is empty, you don't need a count. Again, bad ruby to do this... but maybe consider while array.any?
ruby implicit method return - generally we avoid commands we don't need
It's worth noting that using the techniques above, you can get the content of the method down to 7 reasonably readable lines. If you're allowed to use .inject or .sum instead of while, this whole method becomes 2 lines.
(as HP_hovercraft points out, the ternary operator reduces this down to 1 line. On production code, I'd be tempted to leave it as 2 lines for readability - but that's just personal preference)

You can put the whole thing in one line with a ternary:
def sum_with_while(min, max)
min > max ? -1 : [*(min..max)].inject(0){|sum,x| sum + x }
end

This is one option, cleaning up your code, see comments:
def sum_with_while(range) # pass a range
array = range.to_a
sum, count = 0, 0 # parallel assignment
while count < array.length
sum += array[count]
count += 1
end
sum # no need to return
end
sum_with_while(10..20)
#=> 165
More Rubyish:
(min..max).sum

Rule 1: Choose the right algorithm.
You wish to compute an arithmetic series.1
def sum_with_while(min, max)
max >= min ? (max-min+1)*(min+max)/2 : -1
end
sum_with_while(4, 4)
#=> 4
sum_with_while(4, 6)
#=> 15
sum_with_while(101, 9999999999999)
#=> 49999999999994999999994950
1. An arithmetic series is the sum of the elements of an arithmetic sequence. Each term of the latter is computed from the previous one by adding a fixed constant n (possibly negative). Heremax-min+1 is the number of terms in the sequence and (min+max)/2, if (min+max) is even, is the average of the values in the sequence. As (max-min+1)*(min+max) is even, this works when (min+max) is odd as well.

Related

Stack level too deep in recursion for largest palindrome product question (Project Euler)

I'm trying to implement a recursive solution to the largest palindrome product problem
What I'm trying to do is start both numbers at 999 and iterate down to 100 for num1 and then restart num1 at 999 and iterate num2 down by 1.
The goal is basically to mimic a nested for-loop.
def largest_palindrome_prod(num1 = 999, num2 = 999, largest_so_far = 0)
prod = num1 * num2
largest_so_far = prod if prod > largest_so_far && check_pal(prod)
if num2 == 100
return largest_so_far
elsif num1 == 100
largest_palindrome_prod(num1 = 999, num2 -= 1, largest_so_far)
else
largest_palindrome_prod(num1 -= 1, num2, largest_so_far)
end
end
#I know this function works, just here for reference
def check_pal(num)
num = num.to_s if num.is_a? Integer
if num.length < 2
true
else
num[0] == num[-1] ? check_pal(num[1..-2]) : false
end
end
rb:10:inlargest_palindrome_prod': stack level too deep`
I'm getting this error which is referring to the else statement in the largest_palindrome_prod function, but I can't figure out wast could be causing the stack error.
You don't have an infinite recursion bug. The stack is just running out of space because of the size of your input. To prove this, you can run your same function with the range of 2-digit numbers, instead of the 3-digit ones. It returns fine, which shows that there is no flaw with your logic.
How to get around this? Two options.
Option 1: You could simply not use recursion here (just use a regular nested loop instead)
Option 2: Keep your same code and enable tail call optimization:
# run_code.rb
RubyVM::InstructionSequence.compile_option = {
tailcall_optimization: true,
trace_instruction: false
}
require './palindrome_functions.rb'
puts largest_palindrome_prod
# => 906609
Note, for a reason I don't fully understand, the tail call optimization must be enabled in a different file than the code being run. So if you simply moved the compile_option line to the palindrome_functions.rb file, it wouldn't work.
I cant really give you a full explanation of tail call optimization (look it up on Wikipedia) but from my understanding, its a heavy optimization for recursive functions that only works when the recursive call is at the end of the function body. Your function meets this criteria.
#maxpleaner has answered your question and has shown how you can use recursion that avoids the stack level error. He also mentioned the option (which I expect he favours) of simply looping, rather than employing recursion. Below is one looping solution. The following method is used in the search1.
def check_ranges(range1, range2 = range1)
range1.flat_map do |n|
[n].product((range2.first..[n, range2.last].min).to_a)
end.map { |x,y| x*y }.
sort.
reverse_each.
find do |z|
arr = z.digits
arr == arr.reverse
end
end
Let's first find the largest palindrome of the product of two numbers between 960 and 999 (if there are any):
check_ranges(960..999)
#=> nil
There are none. Note that this calculation was very cheap, requiring the examination of only 40*40/2 #=> 800 products. Next, find the largest palindrome that is equal to the product of two numbers between 920 and 999.
check_ranges(920..999)
#=> 888888
Success! Note that this method re-checks the 800 products we checked earlier. It makes more sense to examine only the cases represented by the following two calls to brute_force:
check_ranges(960..999, 920..959)
#=> 888888
check_ranges(920..959)
#=> 861168
The first call computes 40*40 #=> 1600 products; the second, 800 products.
Of course, we have not yet necessarily found the largest product that is a palindrome. We do, however, have a lower bound on the largest product, which we can use to advantage. Since
888888/999
#=> 889
we infer that if the product of two numbers is larger than 888888, both of those numbers must be at least 889. We therefore need only check:
check_ranges(889..999, 889..919)
#=> 906609
check_ranges(889..919)
#=> 824428
We are finished. This tells us that 906609 is the largest product of two 3-digit numbers that is a palindrome.
The question does not ask what are the two numbers whose product is the largest palindrome, but we can easily find them:
(889..999).to_a.product((889..919).to_a).find { |x,y| x*y == 906609 }
#=> [993, 913]
993*913
#=> 906609
Moreover, let:
a = (889..999).to_a.product((889..919).to_a).map { |x,y| x*y }.
sort.
reverse
Then:
a.index { |n| n == 906609 }
#=> 84
tells us that only the largest 84 elements of this sorted group of 111*31 #=> 3441 products had to be examined before a palindrome (906609) was found.
All of this needs to be organized into a method. Though challenging for a newbie, it should be a good learning experience.
1. It would be useful to test which is faster, arr = z.digits; arr == arr.reverse or s = z.to_s; s == s.reverse.
#maxpleaner already answered, #Cary Swoveland already showed one brute force way using ranges and product. I'd like to show another brute force using a nested loop, easier to follow (IMO):
n = 9999
res = [0]
bottom = 10**(n.digits.size - 1)
n.downto(bottom) do |k|
k.downto(bottom) do |j|
# puts "#{k}, #{j}"
res = [k, j, k * j] if check_pal(k * j) && k * j > res.last
end
end
res
#=> [9999, 9901, 99000099]
I guess it can be optimized further, for example, using
n.downto(n*99/100) do |k|
k.downto(k*99/100) do |j|
Returned [99979, 99681, 9966006699] in 0.7 seconds.
Not required, but this increases the speed:
def check_pal(num)
word = num.to_s
word.reverse == word
end

Understanding this Ruby program concerned with prime numbers

This is a program that came from a textbook:
# Initialize our counter
i = 1
# i: [0, 100]
while (i <= 100)
# Initialize prime flag
prime_flag = true
j = 2
# Test divisibility of i from [0, i/2]
while (j <= i / 2)
# puts " i ==> " to i.to_s + " j ==> " + j.to_s
if (i % j == 0)
prime_flag = false
# break
end
j = j + 1
end
# We found a prime!
if prime_flag
puts "Prime ==> " + i.to_s
end
# Increment the counter
i += 1
end
The while (j <= i / 2) introduces a new loop. What if we are trying to find prime numbers. Why is this written? Prime numbers don't have square roots. What is the purpose of j being <= i / 2? I do not understand why j is introduced.
You are correct that you should be only checking numbers <= floor(sqrt(i)). The above code is unnecessarily checking numbers from ceil(sqrt(i)) through i/2. It would give the correct answer, however.
In addition, this is not very Ruby-like code. It's terrible and the author should feel terrible (unless they intended to show you something bad in order for you to be amazed when you see how you can write it better!).
Here's the same code done in a more Ruby-like manner. Note that prime? can definitely be a one-liner, but I split things on to more lines readability in the context of the question:
def prime?(i) # Define a function that takes 1 parameter `i`
MAX_NUM_TO_CHECK = Math.sqrt(i) # No need to check numbers greater than sqrt(i)
(2..MAX_NUM_TO_CHECK).all? do |j| # Return `true` if the following line is true for
# all numbers [2,MAX_NUM_TO_CHECK]
i % j != 0 # true if `i` is evenly not divisible by `j`. Any
# input that evaluates to false here is not prime.
end
end
# Test primality of numbers [1,100]
(1..100).each {|n| puts "Prime ==> #{n}" if prime? n}
I think the biggest differences between your book and this code are:
The algorithm is different in that we do not check all values, but rather limit the checks to <= sqrt(i). We also stop checking once we know a number is not prime.
We iterate over Ranges rather than keeping counters. This is slightly higher level and easier to read once you get the syntax.
I split the code into two parts, a function that calculates whether a parameter is prime or not, and then we iterate over a Range of inputs (1..100). This seems like a good division of functionality to me, helping readability.
Some language features used here not in your example:
If statements can go after expressions, and the expression is only evaluated if the predicate (the thing after the if) evaluates to true. This can make some statements more readable.
A range is written (x..y) and allows you to quickly describe a series of values that you can iterate over without keeping counters.
Code inside
do |param1, ..., paramN| <CODE>; end
or
{|param1, ..., paramN| <CODE>}
is called a block. It's an anonymous function (a function passed in as a parameter to another function/method). We use this with all? and each here.
each is used to run a block of code on each element of a collection, ignoring the return value
all? can be used to determine whether a block returns true for every item in a collection.
If you're not familiar with passing code into functions, this is probably a little confusing. It allows you to execute different code based on your needs. For example, each runs the yielded block for every item in the collection.You could do anything in that block without changing the definition of each... you just yield it a block and it runs that block with the proper parameters. Here is a good blog post to get you started on how this works and what else you can use it for.

Ruby prime number sum

I am trying to take the sum of the n first prime numbers. I found a way of showing the first 100, but I don't know how to get rid of 1 and how to make a sum with the numbers. I was thinking about storing them into an array, but I can not figure it out.
num = 1
last = 100
while (num <= last)
condition = true
x = 2
while (x <= num / 2)
if (num % x == 0)
condition = false
break
end
x = x + 1
end
primes = [] # Here
if condition
puts num.to_s
primes << num.to_s # Here
end
num = num + 1
end
puts primes.inject(:+) # Here
Based on what I understood from what you guys are saying I added these lines (the ones commented # Here). It still does not print the sum of them. What I meant with getting rid of 1 is that I know that 1 is not considered a prime number, and I do not get how to make it without 1. Thank you very much guys for your time and answers, and please understand that I am just starting to study this.
If you want to add a list of numbers together you can use the following:
list_of_prime_numbers.inject(0) {|total,prime| total + prime}
This will take the list of numbers, and add them one by one to an accumulator (total) that was injected into the loop (.inject(0)), add it to the current number (prime) and then return the total which then becomes the value of total in the next iteration.
I'm not quite sure what you mean by:
I don't know how to get rid of 1
but if you mean to not use the first number (which is 1 in a list of primes starting from 0)
then you could do:
list_of_prime_numbers[1...list_of_prime_numbers.length].
inject(0) {|total,prime| total + prime}
Which would only get all the numbers except the first up to but not including the length of the array
and as for getting the number into the array you could push it into the array like so:
list_of_prime_numbers << prime_number
You can make use of Prime Enumerable in ruby
require 'prime'
((1..100).select { |number| Prime.prime?(number) }).inject(:+)
OR
Prime.each(100).inject(:+)
Hope this helps.

I need help on understading: Write a method, sum which takes an array of numbers and returns the sum of the numbers

I've been studying ruby and have been taking some exercises to see how much I have learned and I've come across this:
Q: Write a method, sum which takes an array of numbers and returns the sum of the numbers.
The answer was provided for the problem but I don't understand why or how. I would like some help from anyone to explain them for me in simple terms so that I can understand this. Please keep in mind that I'm new to programming. Thank you.
A:
def sum(nums)
total = 0
i = 0
while i < nums.count
total += nums[i]
i += 1
end
# return total
total
end
Let me add some comments to see if this helps...
def sum(nums)
# initialize total to zero
total = 0
# initialize a counter to zero
i = 0
# while the counter is less than the size / count of the array...
while i < nums.count
# add the number at the array index of i to total
# this can also be written: total = total + nums[i]
total += nums[i]
# increment your counter, then loop
i += 1
end
# return total
total
end
The way to do this with ruby is
def sum (nums_array)
nums_array.inject(:+)
end
Equivalently, you could use reduce, which is an alias for inject.
Inject iterates over your array cumulatively applying any binary operation to every element, returning the accumulator (in this case, the sum of all the elements). You could also do something like
nums_array.inject(:-)
nums_array.inject(:*)
nums_array.inject(:%)
and etc.
The best place to test any Ruby method is in IRB or PRY on the command line, or, if you'd rather use something with a GUI and are working on a Mac, CodeRunner is great.
For more on inject / reduce (or any method you come across), the ruby docs are a great resource.
def sum(nums)
total = 0
i = 0 # i is set to `0`, as in Ruby array is 0 based.i will point to the
# first element in the array initially.
while i < nums.count # loop to iterate through the array till the last index come.
total += nums[i] # nums[i] is for accessing the element from the array at index i.
# and adding the value of total in previous iteration to current element
# of the array at i(or to the initial value of total,if it is the first iteration).
i += 1 # this move the i from current index to next index of the array.
end
# return total
total
end
i += 1 is called the syntactic sugar of i=i+1.Same is true for total += nums[i].
This is horrible. Whoever wrote doesn't understand the first thing about Ruby. He doesn't even understand much of programming, apparently. Just forget about it.
This is how a Rubyist or pretty much any other programmer would solve that problem:
def sum(nums)
nums.inject(0, :+)
end
Unlike the code that was provided to you, this doesn't use any concepts outside of some basic math. (Fold and Addition.)

How can I test if a value is a prime number in Ruby? Both the easy and the hard way?

I am trying to create a program that will test whether a value is prime, but I don't know how. This is my code:
class DetermineIfPrime
def initialize (nth_value)
#nth_value = nth_value
primetest
end
def primetest
if Prime.prime?(#nth_value)
puts ("#{#nth_value} is prime")
else
puts ("This is not a prime number.")
end
rescue Exception
puts ("#{$!.class}")
puts ("#{$!}")
end
end
And every time I run that it returns this.
NameError
uninitialized constant DetermineIfPrime::Prime
I tried other ways to do the job, but I think this is the closest I can get.
I also tried this:
class DetermineIfPrime
def initialize (nth_value)
#nth_value = nth_value
primetest
end
def primetest
for test_value in [2, 3, 5, 7, 9, 11, 13] do
if (#nth_value % test_value) == 0
puts ("#{#nth_value} is not divisible by #{test_value}")
else
puts ("This is not a prime number since this is divisible by #{test_value}")
break
end
end
end
end
Or am I just doing something wrong?
Ruby has built in method to check if number is prime or not.
require 'prime'
Prime.prime?(2) #=> true
Prime.prime?(4) #=> false
def is_prime?(num)
return false if num <= 1
Math.sqrt(num).to_i.downto(2).each {|i| return false if num % i == 0}
true
end
First, we check for 0 and 1, as they're not prime. Then we basically just check every number less than num to see if it divides. However, as explained here, for every factor greater than the square root of num, there's one that's less, so we only look between 2 and the square root.
Update
def is_prime?(num)
return if num <= 1
(2..Math.sqrt(num)).none? { |i| (num % i).zero? }
end
The error you are getting is because you haven't required Primein your code, You need to do require Prime in your file.
One cool way I found here, to check whether a number is prime or not is following:
class Fixnum
def prime?
('1' * self) !~ /^1?$|^(11+?)\1+$/
end
end
10.prime?
From an algorithmic standpoint, checking if a number is prime can be done by checking all numbers up to and including (rounding down to previous integer) said number's square root.
For example, checking if 100 is prime involves checking everything up to 10.
Checking 99 means only going to 9.
** Another way to think about it **
Each factor has a pair (3 is a factor of 36, and 3's pair is 12).
The pair is on the other side of the square root (square root of 6 is 36, 3 < 6, 12 > 6).
So by checking everything until the square root (and not going over) ensures you check all possible factors.
You can make it quicker by having a list of prime numbers to compare, as you are doing. If you have a maximum limit that's reasonably small, you could just have a list of primes and do a direct lookup to see if that number is prime.
def is_prime?(num)
Math.sqrt(num).floor.downto(2).each {|i| return false if num % i == 0}
true
end
lol sorry for resurrecting a super old questions, but it's the first one that came up in google.
Basically, it loops through possible divisors, using the square root as the max number to check to save time on very large numbers.
In response to your question, while you can approach the problem by using Ruby's Prime I am going to write code to answer it on its own.
Consider that all you need to do is determine a factor that is smaller than the integer's square root. Any number larger than the integer's square root as a factor requires a second factor to render the number as the product. (e.g. square root of 15 is approx 3.8 so if you find 5 as a factor it is only a factor with the factor pair 3 and 5!!)
def isPrime?(num)
(2..Math.sqrt(num)).each { |i| return false if num % i == 0}
true
end
Hope that helps!!
(To first answer the question: yes, you are doing something wrong. As BLUEPIXY mentions, you need to put require 'prime' somewhere above the line that calls Prime.prime?. Typically on line 1.)
Now, a lot of answers have been given that don't use Prime.prime?, and I thought it might be interesting to benchmark some of them, along with a possible improvement of my own that I had in mind.
###TL;DR
I benchmarked several solutions, including a couple of my own; using a while loop and skipping even numbers performs best.
Methods tested
Here are the methods I used from the answers:
require 'prime'
def prime1?(num)
return if num <= 1
(2..Math.sqrt(num)).none? { |i| (num % i).zero? }
end
def prime2?(num)
return false if num <= 1
Math.sqrt(num).to_i.downto(2) {|i| return false if num % i == 0}
true
end
def prime3?(num)
Prime.prime?(num)
end
def prime4?(num)
('1' * num) !~ /^1?$|^(11+?)\1+$/
end
prime1? is AndreiMotinga's updated version. prime2? is his original version (with the superfluous each method removed). prime3? is Reboot's, using prime library. prime4? is Saurabh's regex version (minus the Fixnum monkey-patch).
A couple more methods to test
The improvement I had in mind was to leverage the fact that even numbers can't be prime, and leave them out of the iteration loop. So, this method uses the #step method to iterate over only odd numbers, starting with 3:
def prime5?(num)
return true if num == 2
return false if num <= 1 || num.even?
3.step(Math.sqrt(num).floor, 2) { |i| return false if (num % i).zero? }
true
end
I thought as well that it might be interesting to see how a "primitive" implementation of the same algorithm, using a while loop, might perform. So, here's one:
def prime6?(num)
return true if num == 2
return false if num <= 1 || num.even?
i = 3
top = Math.sqrt(num).floor
loop do
return false if (num % i).zero?
i += 2
break if i > top
end
true
end
Benchmarks
I did a simple benchmark on each of these, timing a call to each method with the prime number 67,280,421,310,721. For example:
start = Time.now
prime1? 67280421310721
puts "prime1? #{Time.now - start}"
start = Time.now
prime2? 67280421310721
puts "prime2? #{Time.now - start}"
# etc.
As I suspected I would have to do, I canceled prime4? after about 60 seconds. Presumably, it takes quite a bit longer than 60 seconds to assign north of 6.7 trillion '1''s to memory, and then apply a regex filter to the result — assuming it's possible on a given machine to allocate the necessary memory in the first place. (On mine, it would seem that there isn't: I went into irb, put in '1' * 67280421310721, made and ate dinner, came back to the computer, and found Killed: 9 as the response. That looks like a SignalException raised when the process got killed.)
The other results are:
prime1? 3.085434
prime2? 1.149405
prime3? 1.236517
prime5? 0.748564
prime6? 0.377235
Some (tentative) conclusions
I suppose that isn't really surprising that the primitive solution with the while loop is fastest, since it's probably closer than the others to what's going on under the hood. It is a bit surprising that it's three times faster than Prime.prime?, though. (After looking at the source code in the doc it is less so. There are lots of bells and whistles in the Prime object.)
AndreiMotinga's updated version is nearly three times as slow as his original, which suggests that the #none? method isn't much of a performer, at least in this context.
Finally, the regex version might be cool, but it certainly doesn't appear to have much practical value, and using it in a monkey-patch of a core class looks like something to avoid entirely.
If you are going to use any Prime functions you must include the Prime library. This problem can be solved without the use of the prime library however.
def isPrime?(num)
(2..Math.sqrt(num)).each { |i|
if num % i == 0 && i < num
return false
end
}
true
end
Something like this would work.
Try this
def prime?(num)
2.upto(Math.sqrt(num).ceil) do |i|
break if num%i==0
return true if i==Math.sqrt(num).ceil
end
return false
end
So most of the answers here are doing the same thing in slightly different ways which is one of the cool things about Ruby, but I'm a pretty new student (which is why I was looking this up in the first place) and so here's my version with comment explanations in the code:
def isprime n # starting with 2 because testing for a prime means you don't want to test division by 1
2.upto(Math.sqrt(n)) do |x| # testing up to the square root of the number because going past there is excessive
if n % x == 0
# n is the number being called from the program
# x is the number we're dividing by, counting from 2 up to the square root of the number
return false # this means the number is not prime
else
return true # this means the number is prime
end
end
end

Resources