Beginner Ruby Programmer- prints error on a practice problem - ruby

"Write a method reverse_range(min, max) that takes in two numbers min and max. The function should return an array containing all numbers from min to max in reverse order. The min and max should be excluded from the array"
print reverse_range(10, 17) puts print reverse_range(1, 7)
"its printing the wrong output, this is my ruby code"
def reverse_range(min, max)
nums = []
i = max - 1
while i > min
nums << i
i -= 1
end
return
end

You can use direct function
max.downto(min)
OR create function
def reverse_range(min, max)
max.downto(min).collect{|a|a}
end
OR
def reverse_range(min, max)
min.upto(max).collect{|a|a}.reverse
end
OR
def reverse_range(min, max)
(min..max).collect{|a|a}.reverse
end
OR if you want to use your same code, Just add nums after return in end of function body then code will be as
def reverse_range(min, max)
nums = []
i = max - 1
while i > min
nums << i
i -= 1
end
nums # or return nums
end

Related

How to loop over an entire method until you achieve what you want ? (ruby)

I'm learning ruby and practicing with codewars, and I've come to a challenge that I feel I mainly understand (rudimentarily) but I'm unable to figure out how to continue looping over the method until I reach the result I'm looking for.
The challenge is asking to reduce a number, by multiplying its digits, until the multiplication results in a single digit. In the end it wants you to return the number of times you had to multiply the number until you arrived at a single digit. Example -> given -> 39; 3 * 9 = 27, 2 * 7 = 14, 1 * 4 = 4; answer -> 3
Here's my code :
def persistence(n)
if n < 10
return 0
end
arr = n.to_s.split("")
sum = 1
count = 0
arr.each do |num|
sum *= num.to_i
if num == arr[-1]
count += 1
end
end
if sum < 10
return count
else
persistence(sum)
end
end
Thanks for your help!
Your function is looking great with recursion but you are reseting the count variable to 0 each time the loop runs, I think if you use an auxiliar method it should run ok:
this is in base of your code with minor improvements:
def persistence(n)
return 0 if n < 10
count = 0
multiply_values(n, count)
end
def multiply_values(n, count)
arr = n.to_s.chars
sum = 1
arr.each do |num|
sum *= num.to_i
if num == arr[-1]
count += 1
end
end
if sum < 10
return count
else
multiply_values(sum, count)
end
end
a shorter solution could be to do:
def persistence(n)
return 0 if n < 10
multiply_values(n, 1)
end
def multiply_values(n, count)
sum = n.to_s.chars.map(&:to_i).reduce(&:*)
return count if sum < 10
multiply_values(sum, count + 1)
end
and without recursion:
def persistence(n)
return 0 if n < 10
count = 0
while n > 10
n = n.to_s.chars.map(&:to_i).reduce(&:*)
count += 1
end
count
end
Let's look at a nicer way to do this once:
num = 1234
product = num.to_s.split("").map(&:to_i).reduce(&:*)
Breaking it down:
num.to_s.split("")
As you know, this gets us ["1", "2", "3", "4"]. We can easily get back to [1, 2, 3, 4] by mapping the #to_i method to each string in that array.
num.to_s.split("").map(&:to_i)
We then need to multiply them together. #reduce is a handy method. We can pass it a block:
num.to_s.split("").map(&:to_i).reduce { |a, b| a * b }
Or take a shortcut:
num.to_s.split("").map(&:to_i).reduce(&:*)
As for looping, you could employ recursion, and create product_of_digits as a new method for Integer.
class Integer
def product_of_digits
if self < 10
self
else
self.to_s.split("").map(&:to_i).reduce(&:*).product_of_digits
end
end
end
We can now simply call this method on any integer.
1344.product_of_digits # => 6

How to implement Java's Comparable module in Ruby

I'm currently going over Robert Sedgewick's Algorithms book. In the book for the implementation of a Priority Queue there is the use of the Comparable module. While going over the top k frequent elements leetcode problem I noticed that there would be an error in my Ruby implementation.
def top_k_frequent(nums, k)
ans = []
h = Hash.new(0)
nums.each do |num|
h[num] += 1
end
heap = Heap.new
h.each do |k,v|
heap.insert({k => v})
end
k.times do
a = heap.del_max
ans.push(a.keys[0])
end
ans
end
class Heap
def initialize
#n = 0
#pq = []
end
def insert(v)
#pq[#n += 1] = v
swim(#n)
end
def swim(k)
while k > 1 && less((k / 2).floor, k)
swap((k / 2).floor, k)
k = k/2
end
end
def swap(i, j)
temp = #pq[i]
#pq[i] = #pq[j]
#pq[j] = temp
end
def less(i, j)
#pq[i].values[0] < #pq[j].values[0]
end
def del_max
max = #pq[1]
swap(1, #n)
#n -= 1
#pq[#n + 1] = nil
sink(1)
max
end
def sink(k)
while 2 * k <= #n
j = 2 * k
if !#pq[j + 1].nil?
j += 1 if j > 1 && #pq[j].values[0] < #pq[j + 1].values[0]
end
break if !less(k, j)
swap(k, j)
k = j
end
end
end
Above is the Java Priority Queue implementation.
Ruby's comparable operator is <=> which will return one of -1, 0, 1 and nil (nil mean could not compare).
In order to compare two objects , both need to implement a method def <=>(other). This is not on Object, so is not available on any objects that don't implement it or extend from a class that does implement it. Numbers and Strings, for example, do have an implementation. Hashes do not.
I think in your case, the issue is slightly different.
When you call queue.insert(my_hash) what you're expecting is for the algorithm to break up my_hash and build from that. Instead, the algorithm takes the hash as a single, atomic object and inserts that.
If you add something like:
class Tuple
attr_accessor :key, :value
def initialize(key, value)
#key = key
#value = value
end
def <=>(other)
return nil unless other.is_a?(Tuple)
value <=> other.value
end
end
then this will allow you to do something like:
hsh = { 1 => 3, 2 => 2, 3 => 1}
tuples = hsh.map { |k, v| Tuple.new(k, v) }
tuples.each { |tuple| my_heap.insert(tuple) }
you will have all of your data in the heap.
When you retrieve an item, it will be a tuple, so you can just call item.key and item.value to access the data.

Euler 23 in Ruby

All right. I think I have the right idea to find the solution to Euler #23 (The one about finding the sum of all numbers that can't be expressed as the sum of two abundant numbers).
However, it is clear that one of my methods is too damn brutal.
How do you un-brute force this and make it work?
sum_of_two_abunds?(num, array) is the problematic method. I've tried pre-excluding certain numbers and it's still taking forever and I'm not even sure that it's giving the right answer.
def divsum(number)
divsum = 1
(2..Math.sqrt(number)).each {|i| divsum += i + number/i if number % i == 0}
divsum -= Math.sqrt(number) if Math.sqrt(number).integer?
divsum
end
def is_abundant?(num)
return true if divsum(num) > num
return false
end
def get_abundants(uptonum)
abundants = (12..uptonum).select {|int| is_abundant?(int)}
end
def sum_of_two_abunds?(num, array)
#abundant, and can be made from adding two abundant numbers.
array.each do |abun1|
array.each do |abun2|
current = abun1+abun2
break if current > num
return true if current == num
end
end
return false
end
def non_abundant_sum
ceiling = 28123
sum = (1..23).inject(:+) + (24..ceiling).select{|i| i < 945 && i % 2 != 0}.inject(:+)
numeri = (24..ceiling).to_a
numeri.delete_if {|i| i < 945 && i % 2 != 0}
numeri.delete_if {|i| i % 100 == 0}
abundants = get_abundants(ceiling)
numeri.each {|numerus| sum += numerus if sum_of_two_abunds?(numerus, abundants) == false}
return sum
end
start_time = Time.now
puts non_abundant_sum
#Not enough numbers getting excluded from the total.
duration = Time.now - start_time
puts "Took #{duration} s "
Solution 1
A simple way to make it a lot faster is to speed up your sum_of_two_abunds? method:
def sum_of_two_abunds?(num, array)
array.each do |abun1|
array.each do |abun2|
current = abun1+abun2
break if current > num
return true if current == num
end
end
return false
end
Instead of that inner loop, just ask the array whether it contains num - abun1:
def sum_of_two_abunds?(num, array)
array.each do |abun1|
return true if array.include?(num - abun1)
end
false
end
That's already faster than your Ruby code, since it's simpler and running faster C code. Also, now that that idea is clear, you can take advantage of the fact that the array is sorted and search num - abun1 with binary search:
def sum_of_two_abunds?(num, array)
array.each do |abun1|
return true if array.bsearch { |x| num - abun1 <=> x }
end
false
end
And making that Rubyish:
def sum_of_two_abunds?(num, array)
array.any? do |abun1|
array.bsearch { |x| num - abun1 <=> x }
end
end
Now you can get rid of your own special case optimizations and fix your incorrect divsum (which for example claims that divsum(4) is 5 ... you should really compare against a naive implementation that doesn't try any square root optimizations).
And then it should finish in well under a minute (about 11 seconds on my PC).
Solution 2
Or you could instead ditch sum_of_two_abunds? entirely and just create all sums of two abundants and nullify their contribution to the sum:
def non_abundant_sum
ceiling = 28123
abundants = get_abundants(ceiling)
numeri = (0..ceiling).to_a
abundants.each { |a| abundants.each { |b| numeri[a + b] = 0 } }
numeri.compact.sum
end
That runs on my PC in about 3 seconds.

Ruby: Continue adding each value in an array until it reaches the max set value

I can't think of a way on how to sum up the values inside the given array and stops when it reaches the max value. Like the example on below, it should add only 60 and 80. The array could be more than 3 values.
def sum (array, max_value)
#code here
end
puts sum([60, 80, 90], 200)
You can always just cap it with inject:
def sum(array, max_value)
array.inject do |s, v|
s + v <= max_value ? s + v : s
end
end
Since you have control over what value is chained forward, you can stop adding to the sum if it'd exceed your threshold.
Edit: If you're looking for this to break out on longer lists:
def sum (array, max_value)
array.inject do |s, v|
break s if s + v > max_value
s + v
end
end
add = ->(arr, max, current = 0) do
val = arr.shift
arr.empty? || val + current > max ? \
current : add(arr, max, val + current)
end
add.([60, 80, 90], 200)
#⇒ 140
The prevent a mutation of the original array, when passed by reference, one should dup it in advance:
arr, max = [60, 80, 90], 200
add.(arr.dup, max)
FWIW: the solution that does not mutate an input:
add = lambda do |arr, max, current = 0, entry = true|
arr = arr.dup if entry
val = arr.shift
arr.empty? || val + current > max ? \
current : add(arr, max, val + current, false)
end
Ruby is not my first language, but you could do a simple loop:
def msum(arr,m)
i=0
sum=0
arr.each do |e|
sum+=e
break if sum>m
i+=1
end
return arr.take(i)
end

How to create a bubble sort of a double-linked list for Ruby

I have been implementing a bubble sort for a doubly linked list:
def sort2(list) #bubble sort
for i in 0...list.length
for j in 0...list.length-1-i
if list.get(j+1)<list.get(j)
list.swap(j+1, j)
end
end
end
end
I don't have any idea how implement a bucket-sort. We can only use methods like:
get(i) - which return value of i element
swap(i, j) - which swaps two elements
length(list) - return length of list
This is the code for get, swap and length:
def swap(i,j)
if i > j
i, j = j, i
elsif j == i
return
end
tmp = nil
list = #ListE.next #first element
for it in 0...j
if i == it
tmp = list
end
list = list.next
end
tmp.v, list.v = list.v, tmp.v
end
def get(i)
a = #ListE
while i>0
a = a.next
i-=1
end
return a.next.v
end
def length()
list = #ListE.next
length_of_list = 0
while list.v != nil
length_of_list += 1
list = list.next
end
return length_of_list
end
This is my attempt at an insertion sort:
def sort3(list) #insertion sort
for i in 1...list.length
j = i
while j > 0 and list.get(j-1) > list.get(j)
list.swap(j-1, i)
j -= 1
end
end
end

Resources