Basic ruby code not working - ruby

I just learnt Ruby and I am doing some basic practise problems to get familiar with the language. I just came across this question:
"Write a method that takes an array of numbers. If a pair of numbers
in the array sums to zero, return the positions of those two numbers.
If no pair of numbers sums to zero, return nil."
This is my code:
def two_sum(nums)
i = 0
j = 0
while i < nums.length
while j < nums.length
if nums[i] + nums[j] == 0
return [i, j]
end
j+= 1
end
i += 1
end
return nil
end
It returns nil everytime. What's wrong with it?

j should be re-initialized to 0 when i gets incremented:
while i < nums.length
while j < nums.length
if nums[i] + nums[j] == 0
return [i, j]
end
j+= 1
end
i += 1
j = 0 # Here
end

While Yu Hao answers the literal question, here is a more Rubyish solution:
def two_sum(nums)
nums.each_with_index do |x, i|
j = nums.index(-x)
return [i, j] if j
end
nil
end

Related

What's the name of this sorting algorithm?

I searched around a bit and could not found any sorting algorithm that described this way to sort. I do understand that it has no real use as it's terribly inefficient. Here it is in Ruby:
def swap(array, i)
array[i], array[i+1] = array[i+1], array[i]
end
def compare(array, i)
array[i] > array[i+1]
end
def sort(array)
i = 0
until i + 1 == array.length
if compare(array, i)
swap(array, i)
i = 0
else
i += 1
end
end
return array
end
This is Gnome sort kind - walking from the beginning until order violation occurs, then swapping, but here position resets to array begin.

Nuances of where to define a variable in ruby code

I've just started learning ruby, and the position of where variables are defined somewhat elude me. For example, why does this code work:
def two_sum(nums)
result = nil
i = 0
while i < nums.length
k = (nums.length - 1)
if nums[i] + nums[k] == 0
result = [i,k]
end
i += 1
k -= 1
end
return result
end
And why does this code not work:
def two_sum(nums)
result = nil
i = 0
k = (nums.length - 1)
while i < nums.length
if nums[i] + nums[k] == 0
result = [i,k]
end
i += 1
k -= 1
end
return result
end
Thank you in advance!
I think you code might just have a bug
while i < nums.length
k = (nums.length - 1)
...
k -= 1 # this statement has no effect!
end
Above, the value if k is always (nums.length - 1) because you reassign it at the begin of each iteration. The other statement has no effect.
k = (nums.length - 1)
while i < nums.length
...
k -= 1
end
Above, the value of k starts at (nums.length - 1) in the first iteration and is then reduced by 1 for each iteration.
Pro tipp —
It is very unusual in Ruby to use a for/while/until loop. If you want to loop over all elements use each or each_with_index instead
array.each { |each| ... }
array.each_with_index { |each, n| ... }

Ruby longest palindrome - why does a slight modification in a while loop break my code?

I'm trying to solve this Ruby problem and I can't figure out why having a minor while loop difference renders one test false: longest_palindrome("abba") outputs "bb" instead of "abba", which is false. I can only solve it with for and while loops, so please no advanced methods. It's easier to highlight the difference in the code block (first one is the working solution, second is mine. Also assume the palindrome? method is already defined):
def longest_palindrome(string)
best_palindrome = nil
idx1 = 0
***while idx1 < string.length
length = 1
while (idx1 + length) <= string.length
substring = string.slice(idx1, length)***
if palindrome?(substring) && (best_palindrome == nil || substring.length > best_palindrome.length)
best_palindrome = substring
end
length += 1
end
idx1 += 1
end
return best_palindrome
end
def longest_palindrome(string)
longest = nil
i = 0
***while i < string.length
i2 = 1
while i2 < string.length***
if palindrome?(string.slice(i, i2)) == true && (longest == nil || string.slice(i, i2).length > longest.length)
longest = string.slice(i, i2)
end
i2 += 1
end
i += 1
end
return longest
end
This part of your code...
while i2 < string.length
... means you're never checking the maximum possible length.
"abba".slice(0,4) is the entire string, but you only ever go up to "abba".slice(0,3) which is "abb".
So you never test the entire string.
Change the line to...
while i2 <= string.length
...and it should be ok.

Why does one of these Ruby methods result in 'stack overflow' but the other doesn't? (Permutations Algorithm)

Below are two slightly different methods for listing all lexicographic permutations of N objects. I can't understand why the first method works fine for smallish N, but fails above a certain limit and results in 'stack overflow'. The second method; however, works just fine up to my tested limit of 10**6. Thanks in advance for your help and insight!
$count = 0
$permutations = []
def perms(array)
$permutations = array
$count += 1
if array.length <= 1
return $permuations
end
i = (array.length - 2)
until array[i] < array[i+1]
i -= 1
end
if i < 0
return $permutations
end
j = (array.length - 1)
until array[j] > array[i]
j -= 1
end
array[i], array[j] = array[j], array[i]
i += 1
j = (array.length - 1)
until j < i
array[i], array[j] = array[j], array[i]
i += 1
j -= 1
end
while $count <= (10**6)-2
perms(array)
end
end
perms([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
print $permutations
And here's the second method...
perm_limit = (10**6)
$count = 1
def perms(array)
if array.length <= 1
return false
end
i = (array.length - 2)
until array[i] < array[i+1]
i = (i - 1)
end
if i < 0
return false
end
j = (array.length - 1)
until array[j] > array[i]
j = (j - 1)
end
array[i], array[j] = array[j], array[i]
i = (i + 1)
j = (array.length - 1)
until j < i
array[i], array[j] = array[j], array[i]
i = (i + 1)
j = (j - 1)
end
$count += 1
return true
end
array = [0,1,2,3,4,5,6,7,8,9]
while perms(array) == true
if $count == perm_limit
print array
end
end
Again, thanks.
The first code sample you provide is a recursive function:
while $count <= (10**6)-2
perms(array)
end
The function is calling itself, is calling itself, is calling itself until your stack overflows (everytime a function is called, space on stack is allocated).
Your second algorithm does not use a recursive function and so the depth of your stack is only one - your stack is not growing.
For more information see "What is a stack overflow". The question is for Java, but the concept is the same for all stack-based languages.
Recursive vs. iterative
So why are we writing recursive functions/algorithms if they can overflow? Because recursion can model some problems very nicely, and it can be easier to write a recursive algorithm (it's considered more "mathematically beautiful") than an iterative one. If you know that your recursion depth won't be too deep, then recursion might be the preferred method.
On the other hand, an iterative algorithm is usually the preferred if you're worried about your stack space. An iterative function can be easier or harder to write depending on how you model the problem. All recursive functions can be converted to iterative functions.
On a side note: there are some languages where recursion and stack space is not a problem. These languages may use "tail-calls" meaning the function is recursive, but instead of allocating new space on the stack, it simply re-uses the current function's stack space (and so the stack never grows). You can read more here.

Need to make this more Ruby-like

I'm new to Ruby and I seem to be comfortable using while loops. But I would like to simplify my code by possibly using the 'each' method. How would I do this for this particular block of code?
sum_array = []
i = 0
while i < array.length - 1
j = i + 1
while j < array.length
sum = array[i] + array[j]
if sum != 0
sum_array << sum
end
j += 1
end
i += 1
end
sum_array = array.combination(2).map{|n, m| n + m}.reject(&:zero?)
array = (1..10).to_a # test array [1,2,3,4,....10]
sum_array = []
(0...array.length).each do |i| # from 0 to array.length-1
(i+1...array.length).each do |j| # from i+1 to array.length-1
sum = array[i] + array[j]
sum_array << sum unless sum == 0 # brief condition
end
end
def sum_array(input)
[].tap do |sums|
input.each_with_index do |x, index|
tail = input[index.next..-1]
tail.each do |y|
sum = x + y
sums << sum unless sum.zero?
end
end
end
end
puts sum_array([1,2,0,0])
# => [3,1,1,2,2]
You could do this:
sum_array = []
array.each_index do |i|
sum_array += (i+1...array.length).collect { |j| array[i] + array[j] }
end
sum_array.reject!(&:zero?)

Resources