Ruby: nil can't be coerced into Fixnum (TypeError) - ruby

The error is on line 12 and I'm not sure why I can't add the numbers. Any help is much appreciated.
Instructions: 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.
def two_sum(nums)
idx1 = 0
idx2 = 1
while idx1 < nums.length
if nums[idx1] + nums[idx2] == 0
return [idx1, idx2]
end
idx2 += 1
if idx2 == nums.length
idx1 += 1
idx2 = idx1 + 1
end
end
return nil
end
puts("two_sum([1, 3, 5, -3]) == [1, 3]: #{two_sum([1, 3, 5, -3]) == [1, 3]}")
puts("two_sum([1, 3, 5]) == nil: #{two_sum([1, 3, 5]) == nil}")

idx2 could overflow capacity of your array:
Imagine. nums = [1,2,3], so nums.length is 3, idx1 = 1, idx2 = 2
idx2 += 1 # ok now idx2 is 3
if idx2 == nums.length # ok true, idx2 == 3
idx1 += 1 # mmm, cool idx1 now 2
idx2 = idx1 + 1 # idx2 is 3
end
So in next iteration you will call
nums[idx2]
# same as
nums[3]
# ERROR! there is only 3 numbers in nums
And try to understand this code
def two_sums(nums)
nums[0..-2].each.with_index do |n,i|
nums[i+1..-1].each.with_index do |m,j|
return [i, i+j+1] if m + n == 0
end
end
nil
end

Related

Comparing two arrays with each other

I am trying to solve some problems in ruby get a hold.
I am trying compare two arrays with each other.
Array1 = [1,0,1,0,1,1]
Array2= [0,0,1,0,1,0]
I am getting this input from the user. Then I am comparing the votes. If both persons have upvoted 1 at same index, I am trying increment an empty array by 1.
def count_votes
bob_votes = gets.chomp
alice_votes = gets.chomp
bvotes = bob_votes.split('')
avotes = alice_votes.split('')
common_upvotes = []
bvotes.each.with_index(0) do |el, i|
if bvotes[i] == 1
common_upvotes << 1
end
end
I actually want to compare avotes with bvotes and then increment empty array by 1. I need a little help
You can use Array#zip and Enumerable#count:
array1 = [1,0,1,0,1,1]
array2= [0,0,1,0,1,0]
array1.zip(array2)
#⇒ [[1, 0], [0, 0], [1, 1], [0, 0], [1, 1], [1, 0]]
array1.zip(array2).count { |v1, v2| v1 == v2 && v1 == 1 }
#⇒ 2
or (credits to #engineersmnky):
array1.zip(array2).count { |v1, v2| v1 & v2 == 1 }
or even better (credits to #Stefan):
array1.zip(array2).count { |values| values.all?(1) }
or
array1.
zip(array2).
reject { |v1, v2| v1 == 0 || v2 == 0 }.
count
#⇒ 2
Sidenote: capitalized Array1 declares a constant. To declare a variable, use array1 instead.
The number of indices i for which Array1[i] == 1 && Array2[i] == 1 is
Array1.each_index.count { |i| Array1[i] == 1 && Array2[i] == 1 }
#=> 2
The array of indices i for which Array1[i] == 1 && Array2[i] == 1 is
Array1.each_index.select { |i| Array1[i] == 1 && Array2[i] == 1 }
#=> [2, 4]
The number of indices i for which Array1[i] == Array2[i] is
Array1.each_index.count { |i| Array1[i] == Array2[i] }
#=> 4
If you want to build a new array tracking the index where there is a match of upvotes:
a1 = [1,0,1,0,1,1]
a2= [0,0,1,0,1,0]
p [a1, a2].transpose.map {|x| x.reduce(:&)}
#=> [0, 0, 1, 0, 1, 0]
For just counting, this is another way:
a1 = [1,0,1,0,1,1]
a2= [0,0,1,0,1,0]
votes = 0
a1.each_with_index do |a1, idx|
votes +=1 if (a1 + a2[idx]) == 2
end
p votes #=> 2
In one line:
a1.each_with_index { |a1, idx| votes += 1 if (a1 + a2[idx]) == 2 }

Ruby: Why is my Code false?

Trying to multiply each number by array position, and it's coming out false:
def the_sum(number)
i = 0
number = 0
ans = 0
while i < 0
ans = string[idx] * string.index
i += idx
end
return ans
end
test =
the_sum([2, 3]) == 3 # (2*0) + (3*1)
the_sum([2, 3, 5]) == 13 # (2*0) + (3*1) + (5*2)
and it comes out false?
There are a few problems here
def the_sum(number)
i = 0
number = 0 # You just cleared your input variable!
ans = 0
while i < 0 # You previously i = 0 so this will never be true
ans = string[idx] * string.index
i += idx
end
return ans # Ans is and was always 0
end
This can be fixed by calling each_with_index on the Array that you're passing.
def the_array_sum(array)
ans = 0
array.each_with_index do |val, index|
ans += val * index
end
return ans
end
the_array_sum([2, 3]) == 3
# => true
the_array_sum([2, 3, 5]) == 13
# => true

Placement of variable declaration in Ruby (beginner)

I'm working through some online practice problems to learn Ruby, and while I was able to solve this one, I'm struggling to understand something about the placement of variable declaration.
Why does the following code work when I declare/define "pair" (sum of array indices) inside the idx2 while-loop, but not when I do so directly after declaring the indices themselves?
def two_sum(nums)
idx=0
idx2=0
while idx<nums.length-1
idx2=idx+1
while idx2<nums.length
pair=nums[idx]+nums[idx2]
if pair==0
return [idx, idx2]
else
idx2+=1
end
end
idx+=1
end
end
The version above works, but the structure below does not.
def two_sum(nums)
idx=0
idx2=0
pair=nums[idx]+nums[idx2]
while idx<nums.length-1
idx2=idx+1
while idx2<nums.length
if pair==0
return [idx, idx2]
else
idx2+=1
end
end
idx+=1
end
end
If anyone can provide an explanation or some entry-level resources about this, I'd greatly appreciate it. Thanks.
Edit:
Sorry for indentation and specificity issues regarding desired output. I'm entirely new to this and sometimes details slip by, I appreciate the feedback. Thanks for the step-by-step logical run through, that's exactly what I was looking for.
Let's look at the working code and the broken code one at a time.
Let's say nums = [1, 2, -1, 3]
Supposably Working Code
1 def two_sum(nums)
2 idx = 0
3 idx2 = 0
4
5 while idx < nums.length-1
6 idx2 = idx+1
7 while idx2 < nums.length
8 pair = nums[idx] + nums[idx2]
9 if pair == 0
10 return [idx, idx2]
11 else
12 idx2 += 1
13 end
14 end
15 idx += 1
16 end
17 end
When we start off
idx = 0, idx2 = 0
Now we are in the first while loop (line 6)
idx = 0, idx2 = 1
2nd while loop (line 8)
idx = 0, idx2 = 1, pair = nums[0] + nums[1] = 3
pair != 0, so we are now in the else statement. (line 12)
idx = 0, idx2 = 2, pair is still 3
We now loop back to the 2nd while loop (line 8 again)
idx = 0, idx2 = 2, pair = nums[0] + nums[2] = 0
pair == 0, so we return [0, 2] (line 10)
This is how the code is suppose to run.
Broken Code
1 def two_sum(nums)
2 idx = 0
3 idx2 = 0
4 pair = nums[idx] + nums[idx2]
5 while idx < nums.length-1
6 idx2 = idx+1
7 while idx2 < nums.length
8
9 if pair == 0
10 return [idx, idx2]
11 else
12 idx2 += 1
13 end
14 end
15 idx += 1
16 end
17 end
We will run through the same logic again.
Before we hit the first while loop (line 2 - 4)
idx = 0, idx2 = 0, pair = nums[0] + nums[0] = 2
Now we are in the first while loop, (line 6)
idx = 0, idx2 = 1, pair = 2
And now in second while loop, pair != 0, so we hit the else statement, (line 12)
idx = 0, idx2 = 2, pair = 2
Now we loop back to the start of the second while loop. pair != 2, so we hit the else statement.
idx = 0, idx2 = 3, pair = 2
pair != 0, so we hit the else statement.
idx = 0, idx2 = 4, pair = 2
So now, idx2 < nums.length is false, so we exit the second while loop, and nowidx = 1`, and we continue to cycle.
As you can see, because you declared pair outside of the while loop, it never recalculates to different values, so you will never hit the if statement, because pair will never equal zero, unless of course, you get 0 on the initial sum.
while loops are meant for cases where you are not sure how many loops you need. An example is checking a user's entry, where you may need to loop once, or ten times, depending on when the user gets the entry correct. In this case, you know exactly how many times you need to run. So, an iterator is better for the job here.
Here's an example of how that can be written. Keep in mind there's probably better ways to do this, I just want to show an example.
def two_sum(nums)
nums.each_with_index do |num1, idx1|
nums.each_with_index do |num2, idx2|
next if idx1 == idx2
return [idx1, idx2] if num1 + num2 == 0
end
end
end

Ruby FizzBuzz using arrays, my logic seems right but it is getting an error

FizzBuzz, a classic problem, returns all the numbers up to N with a slight twist. If a number is divisible by 3, it is replaced with "fizz". If it's divisible by 5, it's replaced with "buzz". If it's divisible by both, it's replaced with "fizzbuzz"
I keep getting this Error message:
comparison of Fixnum with nil failed
Can someone explain this error message to me please? Also why is the code not working?
def fizz_buzz(n)
arr = (1..n).to_a
i = 0
while arr[i] < arr[n]
if i % 3 == 0 && i % 5 == 0
arr[i] = 'fizzbuzz'
elsif i % 3 == 0
arr[i] = 'fizz'
elsif i % 5 == 0
arr[i] = 'buzz'
else
arr[i] = i
i += 1
end
end
return arr
end
fizz_buzz(12)
Your conditions are just a bit off, give this a try:
def fizz_buzz(n)
arr = (1..n).to_a
i = 0
while i < n
if arr[i] % 3 == 0 && arr[i] % 5 == 0
arr[i] = 'fizzbuzz'
elsif arr[i] % 3 == 0
arr[i] = 'fizz'
elsif arr[i] % 5 == 0
arr[i] = 'buzz'
end
i+=1
end
return arr
end
Trying to access arr[n] puts you outside the bounds of the array which returns nil in Ruby.
You can update the code the ruby way, by using blocks and guards, I don't remember last time I used a while loop in ruby :)
Also, Array.new accepts a block as an argument which you can exploit to build your Array in a single step:
def fizz_buzz(n)
Array.new(n) do |index|
x = index + 1
case
when x % 3 == 0 && x % 5 == 0 then "fizzbuzz"
when x % 3 == 0 then "fizz"
when x % 5 == 0 then "buzz"
else x
end
end
end
Notice I used 1 as a base index and not 0, you can just remove x = index + 1 and replace x with index to have it working in a zero index base
A solution with a block instead of the while loop, and guards
def fizz_buzz(n)
arr = (1..n).to_a
0.upto(n - 1) do |i|
arr[i] = "fizzbuzz" and next if i % 3 == 0 && i % 5 == 0
arr[i] = "fizz" and next if i % 3 == 0
arr[i] = "buzz" if i % 5 == 0
end
arr
end
#brad-melanson beat me to the straight-forward answer to your question, so I'll share an answer which uses some common Ruby idioms (passing a range to the Array constructor and map), which simplify things, prevent you from having to do any iteration bookkeeping and prevent the possibility of off-by-one errors, out-of-bounds errors, etc.
def fizz_buzz(n)
Array(1..12).map do |n|
if n % 3 == 0 && n % 5 == 0
'fizzbuzz'
elsif n % 3 == 0
'fizz'
elsif n % 5 == 0
'buzz'
else
n
end
end
end
result = fizz_buzz 12
# result => [1, 2, "fizz", 4, "buzz", "fizz", 7, 8, "fizz", "buzz", 11, "fizz"]

Please explain this Ruby method that returns number of repeat letters

Can anybody please explain this code? I don't understand specifically:
elsif idx2 > idx1
is_repeat = true
end
Why are we comparing indices to determine if a letter has been
repeated?
Also what does the 'next' term do inside of the if statement?
The full code is shown below:
# Write a method that takes in a string and returns the number of
# letters that appear more than once in the string. You may assume
# the string contains only lowercase letters. Count the number of
# letters that repeat, not the number of times they repeat in the
# string.
#
# Difficulty: hard.
def num_repeats(array)
repeats = 0
idx1 = 0
while idx1 < array.length
is_repeat = false
idx2 = 0
while idx2 < array.length
if array[idx1] != array[idx2]
idx2 += 1
next
elsif idx2 < idx1
# will have previously counted this repeat
break
elsif idx2 > idx1
is_repeat = true
end
idx2 += 1
end
if is_repeat
repeats += 1
end
idx1 += 1
end
return repeats
end
If both conditions before (if idx2 < array.length and elsif idx2 < idx1) are false but idx2 > idx1 is true, than set the local variable is_repeat to true...

Resources