Iteration order - ruby

I'm working on Project Euler problem #4:
A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.
Find the largest palindrome made from the product of two 3-digit numbers.
My code as follows is wrong:
def ispalindrome?(number)
number.to_s == number.to_s.reverse
end
palindromes = []
(100..999).each { |x|
(100..999).each { |y|
palindromes.push (x * y) if ispalindrome?(x * y)
}
}
palindromes.last # => 580085
What's going on here?

This has nothing to do with ruby. Simple math :)
Replace palindromes.last with palindromes.max

As someone else said, replacing palindromes.last with palindromes.max will work.
The reason is that, as products of three-digit numbers, 580085 = 995 * 583 and 906609 = 993 * 913.
Think carefully about the order in which you consider pairs of x and y. If you consider (993, 913) and then later (995, 583) (as happens in the first and third examples), then the last palindrome found will be 580085.

You just forgot to sort your array before taking the value, I used your code from the first try just added
palindromes.sort
and it gave me 906609

The problem is that you are not returning the biggest number but the last number that was added , and it depends on the order you loop through the numbers.
you need to change your last command to:
puts palindromes.max

Related

How could I DRY this while loop?

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.

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.

How to get the randrange equivalent of python in Ruby

I want to get a random value between 0 and 20 but skips by 3, like the python equivalent of:
random.randrange(0,20, 3)
Here's a one-liner:
(0...20).to_a.keep_if {|z| z % 3 == 0}.sample
And bjhaid's example will work if you make the top number the first number that is equal or greater that is divisible by 3, i.e.:
rand(21 / 3) * 3
But you would have to manually set that upper number depending on what your slice size and upper number are.
My one-liner is kind of ugly to me, if I were using it in just one place in an entire program I might use it. but if I was going to re-use it I'd make a method: edit I just noticed #cremno answer in the comments. I like their step version better than mine. I'd use that in a method:
def randrange(lower, upper, grouping)
(lower...upper).step(grouping).to_a.sample
end
my old method...
def randrange(lower, upper, grouping)
arr = (lower...upper).to_a.keep_if {|i| i % grouping == 0}
arr.sample
end

All possible products

I'm trying to find all possible product of two 3-digit numbers. When I work with small ranges, I'm able to get an output in short amount of time but when the ranges are big, it seems to take really long time. Is there any way to to shorten the time to get the result?
The problem I'm working on is:
"A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.
Find the largest palindrome made from the product of two 3-digit numbers."
a = []
for x in 100..999
for y in 100..999
num = (x * y)
unless a.include? num
a.push num
end
end
end
p a
This is going to compute 100 x 101 and 101 x 100 separately, even though they're not going to be pushed to the array since they're already in it.
I'm bad at math, but maybe every time x goes up, y's minimum range can go up since that one was just used? people who are better at math can tell me if this is going to start missing numbers.
z= 100
for x in 100..999
for y in z..999
num = (x * y)
unless a.include? num
a.push num
end
z = z+1
end
end
I think doing this might make the "unless a.include? num" line unnecessary, too.
Looking at your code a quick optimization you can make is to use a set rather than an array to store the already computed products.
Since a is an array, a.include?(num) will have to iterate through the entire list of elements before returning true / false.
If a were to be a set, a.include?(num) will return in sub linear time.
Example:
require 'set'
a = Set.new
for x in 100..999
for y in 100..999
num = (x * y)
unless a.include? num
a.add(num)
end
end
end
puts a.to_a.join(", ")
Moreover one of the nice properties of a set is that it only stores unique elements so the following would be equivalent:
require 'set'
a = Set.new
for x in 100..999
for y in 100..999
num = (x * y)
a.add(num)
end
end
puts a.to_a.join(", ")
What are you really trying to do, i.e. what is the original problem, and why do you need all of these products?
Are you printing every single one out? Is someone asking you for a concrete list of every single one?
If not, there is likely a better way to deal with this problem. For example, if all you wanted is to check if a number X will be an element in "that list of products", all you'd have to do is:
range = 100..999
range.any? { |i| range.include?(x / i) }

Ruby Permutation (Builtin) - Result does not contain adjacent identical letters

Thank you for your help yesterday and for teaching me something new as well. :)
I have another question based on permutation... the algorithm I have works however I have the issue that identical adjacent characters are missing from the list generated.
For example, if I have the character list a-z,0-9,- and let's say that the maximum length is 2, then I should see aa, bb, cc, dd, ee, ff, etc. ad nauseum.
length = 1
alphabet = [('a'..'z').to_a, ('0'..'9').to_a, ('-').to_a].flatten
prefix = 'file-'
suffix = '.txt'
while length < 3
alphabet.permutation(length).each do |x|
#name = prefix+x.join('').to_s+suffix
puts #name
end
length += 1
end
However, I am only seeing the following:
file-ba.txt
file-bc.txt
note the missing "bb" and this continues on until the program is finished.
I am sure I am missing something, just not sure what?
I think you want to use repeated_permutation instead of permutation.
http://www.ruby-doc.org/core/classes/Array.html#M000289
It will generate all permutations including "file-bb.txt".
That's what a permutation is. The only 6 permutations of [1,2,3] are
123
132
213
231
312
321

Resources