Lychrel numbers - ruby

First of all, for those of you, who don't know (or forgot) about Lychrel numbers, here is an entry from Wikipedia: http://en.wikipedia.org/wiki/Lychrel_number.
I want to implement the Lychrel number detector in the range from 0 to 10_000. Here is my solution:
class Integer
# Return a reversed integer number, e.g.:
#
# 1632.reverse #=> 2361
#
def reverse
self.to_s.reverse.to_i
end
# Check, whether given number
# is the Lychrel number or not.
#
def lychrel?(depth=30)
if depth == 0
return true
elsif self == self.reverse and depth != 30 # [1]
return false
end
# In case both statements are false, try
# recursive "reverse and add" again.
(self + self.reverse).lychrel?(depth-1)
end
end
puts (0..10000).find_all(&:lychrel?)
The issue with this code is the depth value [1]. So, basically, depth is a value, that defines how many times we need to proceed through the iteration process, to be sure, that current number is really a Lychrel number. The default value is 30 iterations, but I want to add more latitude, so programmer can specify his own depth through method's parameter. The 30 iterations is perfect for such small range as I need, but if I want to cover all natural numbers, I have to be more agile.
Because of the recursion, that takes a place in Integer#lychrel?, I can't be agile. If I had provided an argument to the lychrel?, there wouldn't have been any changes because of the [1] statement.
So, my question sounds like this: "How do I refactor my method, so it will accept parameters correctly?".

What you currently have is known as tail recursion. This can usually be re-written as a loop to get rid of the recursive call and eliminate the risk of running out of stack space. Try something more like this:
def lychrel?(depth=30)
val = self
first_iteration = true
while depth > 0 do
# Return false if the number has become a palindrome,
# but allow a palindrome as input
if first_iteration
first_iteration = false
else
if val == val.reverse
return false
end
# Perform next iteration
val = (val + val.reverse)
depth = depth - 1
end
return true
end
I don't have Ruby installed on this machine so I can't verify whether that 's 100% correct, but you get the idea. Also, I'm assuming that the purpose of the and depth != 30 bit is to allow a palindrome to be provided as input without immediately returning false.
By looping, you can use a state variable like first_iteration to keep track of whether or not you need to do the val == val.reverse check. With the recursive solution, scoping limitations prevent you from tracking this easily (you'd have to add another function parameter and pass the state variable to each recursive call in turn).

A more clean and ruby-like solution:
class Integer
def reverse
self.to_s.reverse.to_i
end
def lychrel?(depth=50)
n = self
depth.times do |i|
r = n.reverse
return false if i > 0 and n == r
n += r
end
true
end
end
puts (0...10000).find_all(&:lychrel?) #=> 249 numbers

bta's solution with some corrections:
class Integer
def reverse
self.to_s.reverse.to_i
end
def lychrel?(depth=30)
this = self
first_iteration = true
begin
if first_iteration
first_iteration = false
elsif this == this.reverse
return false
end
this += this.reverse
depth -= 1
end while depth > 0
return true
end
end
puts (1..10000).find_all { |num| num.lychrel?(255) }
Not so fast, but it works:
code/practice/ruby% time ruby lychrel.rb > /dev/null
ruby lychrel.rb > /dev/null 1.14s user 0.00s system 99% cpu 1.150 total

Related

How can I do the opposite .include?

So the goal here is to print the index of the element if the element is in the array or print -1 if the element is not in the array. I have to do this using loops. PLEASE HELP!
def element_index(element, my_array)
while my_array.map.include? element do
puts my_array.index(element)
break
end
until my_array.include? element do
puts -1
break
end
end
p element_index("c", ["a","b","c"])
If it's OK to use Array#index, then
def element_index(elem, collection)
collection.index(elem) || -1
end
Or if it's a homework that you should not use Array#index, or you want to do this on arbitrary collections, then
def element_index(elem, collection)
collection.each_with_index.reduce(-1) do |default, (curr, index)|
curr == elem ? (return index) : default
end
end
By the way, I always turn to Enumerable#reduce when I want to iterate over a collection (array, map, set, ...) to compute one value.
This is an easy way but maybe it doesn't meet the criteria for "using loops":
def element_index(x, arr)
arr.index(x) || -1
end
element_index("c", ["a","b","c"]) #=> 2
element_index("d", ["a","b","c"]) #=> -1
To explicitly use a loop:
def element_index(x, arr)
arr.each_index.find { |i| arr[i] == x } || -1
end
As pointed out in the comments, we could instead write
arr.each_index.find(->{-1}) { |i| arr[i] == x }
element_index("c", ["a","b","c"]) #=> 2
element_index("d", ["a","b","c"]) #=> -1
I know this is an assignment, but I'll first cover this as if it were real code because it's teaching you some not-so-great Ruby.
Ruby has a method for doing this, Array#index. It returns the index of the first matching element (there can be more than one), or nil.
p ["a","b","c"].index("c") # 2
p ["a","b","c"].index("d") # nil
Returning -1 is inadvisable. nil is a safer "this thing does not exist" value because its never a valid value, always false (-1 and 0 are true in Ruby), and does not compare equal to anything but itself. Returning -1 indicates whomever came up with this exercise is converting it from another language like C.
If you must, a simple wrapper will do.
def element_index(element, array)
idx = array.index(element)
if idx == nil
return -1
else
return idx
end
end
I have to do this using loops.
Ok, it's homework. Let's rewrite Array#index.
The basic idea is to loop through each element until you find one which matches. Iterating through each element of an array is done with Array#each, but you need each index, that's done with Array#each_index. The element can be then gotten with array[idx].
def index(array, want)
# Run the block for each index of the array.
# idx will be assigned the index: 0, 1, 2, ...
array.each_index { |idx|
# If it's the element we want, return the index immediately.
# No need to spend more time searching.
if array[idx] == want
return idx
end
}
# Otherwise return -1.
# nil is better, but the assignment wants -1.
return -1
end
# It's better to put the thing you're working on first,
# and the thing you're looking for second.
# Its like verb( subject, object ) or subject.verb(object) if this were a method.
p index(["a","b","c"], "c")
p index(["a","b","c"], "d")
Get used to using list.each { |thing| ... }, that's how you loop in Ruby, along with many other similar methods. There's little call for while and for loops in Ruby. Instead, you ask the object to loop and tell it what to do with each thing. It's very powerful.
I have to do this using loops.
You approach is very creative. You have re-created an if statement using a while loop:
while expression do
# ...
break
end
Is equivalent to:
if expression
# ...
end
With expression being something like array.include? element.
How can I do the opposite?
To invert a (boolean) expression, you just prepend !:
if !expression
# ...
end
Applied to your while-hack:
while !expression do
# ...
break
end
The whole method would look like this:
def element_index(element, my_array)
while my_array.include? element do
puts my_array.index(element)
break
end
while !my_array.include? element do
puts -1
break
end
end
element_index("c", ["a","b","c"])
# prints 2
element_index("d", ["a","b","c"])
# prints -1
As I said at the beginning, this approach is very "creative". You are probably supposed to find the index using a loop (see Schwern's answer) instead of calling the built-in index.

ruby how could i make this factorization recursive till i end with a binary number?

i have this code, basically first i factorize for example the number 28 to:
[2,2,7]
and then i make a list of prime numbers and find the index of each factor in that list, so 2 is prime number with index 0 and 7 prime number with index 2 so it ends up like this:
[[0],[0],[2]]
with which another recursion would be:
[[0],[0],[[0]]]
which tranlated to binary would be:
1101101110111
but im stuck on this:
require 'prime'
def f(n)
Prime.prime_division(n).flat_map { |factor, power| [factor] * power }
end
n=rand(10000)
puts n
f=f (n)
require 'prime'
#list=Prime.take(10000)
g=[]
j=0
f.each do |j|
if j>10
i=f(#list.index(j))
g.push i
i=[]
else
g.push j
end
end
print g
You want to learn, so I won't do all the work for you.
Step 1
Please write those 3 methods :
def get_factors(integer)
# return an Array of Integers:
# get_factors(28) -> [2,2,7]
end
def get_factor_index(prime)
# return the index of prime in Prime.all :
# 2 -> 0
# 7 -> 2
end
def array_to_binary(nested_array)
# convert nested_array (with 0s in leaves) to binary
# [[0],[0],[[0]]] -> "1101101110111"
# Hint : Use Array#to_s, and then String#gsub 3 times to convert ',' to '', and '[' or ']' to 1
end
and come back once you're done. We'll work on the recursion.
Step 2
I modified a bit your answer just a bit. To make it clearer, I tried to use different names for variables and methods. Also, the last line of a method is returned automatically by Ruby. You don't need to define an extra variable. Methods could probably be written more efficiently but I didn't want you to not recognize your code.
Your get_factor_index does more than what I asked for BTW. I'm not sure we can use it like this :
require "prime"
def get_factors(integer)
Prime.prime_division(integer)
end
def nested_array(factors)
factors.flat_map { |factor, power| [factor] * power }
end
def get_factor_index(nested_array)
list=Prime.take(10000)
temp=[]
nested_array.each do |i|
p = list.index(i)
temp.push(p)
end
temp
end
def array_to_binary(array)
temp=array.to_s
temp=temp.gsub("[","1")
temp=temp.gsub("]","1")
temp=temp.gsub(",","")
temp.gsub(" ","")
end
Now, please write a method that uses all the above ones, converting 512 to "10000000001". I'm not sure it's the correct answer, but we'll work on that later.
Also, try this method on 20 (not 28!) and see what you get. Using the above methods, you could try to manually tailor a way to get [[0],[0],[2]]. It's not a problem if it just works for 20 at first.
If you're feeling adventurous, try to get [[0],[0],[[0]]] with the above methods.

For loop... Forever

I have a for loop that I would like to have increment forever.
My code:
for a in (0...Float::INFINITY).step(2)
puts a
end
Output:
0.0
2.0
4.0
Etc. Always with "#{a}.0"
Is there any way to express infinity as an integer, so that the output does not have a .0 at the end without preforming any operations on the contents of the loop?
Addendum
Could you also explain how your loop works? I am trying to find the most efficient solution, because since this loop will be iterating infinity, a few milliseconds shaved off will improve the performance greatly.
Also...
I will accept the solution that takes to shortest time to run to 1000000
According to benchmark both #Sefan and the while loop answers take the same ammount of timeFruity the while loop answers take a bit shorter, with the for loop answers in second, but the multiple loop do answers take far longer.
Since the reason why is out of the scope of this question, I have created another question that addresses why some loops are faster than others (https://stackoverflow.com/questions/33088764/peddle-to-the-metal-faster-loop-faster).
You can use Numeric#step without passing a limit:
0.step(by: 2) { |i| puts i }
Output:
0
2
4
6
...
You can also build your own Enumerator:
step2 = Enumerator.new do |y|
a = 0
loop do
y << a
a += 2
end
end
step2.each { |i| puts i }
You can use while true for that:
puts a = 0
puts a+=2 while true
BTW,
Is there any way to express infinity as an integer
NO
require 'bigdecimal'
(0..BigDecimal('Infinity')).step(2).each{ |n| puts n }
OR
require 'bigdecimal'
for a in (0...BigDecimal::INFINITY).step(2)
puts a
end
This is what the loop method is designed for. loop has no condition for which to run. It will run indefinitely and the only way to exit is to use the keyword break. (or raise a StopIteration)
a = 0
loop { puts a += 2}
This loop will be infinite as there is no break specified.
break can be specified very similarly to how the other answers use the while condition if needed:
a = 0
loop do
puts a += 2
break if a > 1_000_000
end
This loop will now exit once the value of a exceeds 1M.
That being said #Stefan's answer is more efficient as it does not store this integral value or have to perform any additional assignment but rather the number is simply yielded from an Enumerator and discarded it afterwards. The usefulness of this becomes more a matter of your implementation and purpose for this loop.
Try this:
arr = [0]
arr.cycle(1000000) { |i| puts arr[0] +=2 }
If you want infinite loop, then, don't pass any parameter to cycle
arr = [0]
arr.cycle { |i| puts arr[0] +=2 }
a = [-2]
puts a.unshift(a.shift+2) while 'loop forever'

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.

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