NoMethodError undefined method empty? for NilClass - ruby

I am trying to implement a merge sort algorithm. I have the following code:
def merge_sort(array)
if array.length < 2
return array
else
length = array.length
i = array[0..array.length/2-1]
j = array[array.length/2 .. -1]
first = merge_sort(i)
second = merge_sort(j)
sorted_array = []
until first.empty? || second.empty? do
if first[0] >= second[0]
sorted_array << second.shift
else
sorted_array << first.shift
end
end
end
end
I get a NoMethodError for NilClass with it.
From my understanding, the unless block should check for empty array, and stop execution before a Nil class ever occurs.
Why do I get this error?

If array.length < 2 then your merge_sort will return array. Otherwise, merge_sort will return whatever until some_condition do ... end evaluates to. It so happens that until evaluates to nil so your method behaves like this:
def merge_sort(array)
if array.length < 2
return array
else
# Do a bunch of stuff...
return nil
end
end
That means that first and second will be nil most of the time and there's your NoMethodError. Perhaps you want to return sorted_array after your until:
def merge_sort(array)
if array.length < 2
array
else
#...
sorted_array = []
until first.empty? || second.empty? do
#...
end
sorted_array # <------------------- sort of important
end
end

Related

Can't format "Add Two Numbers" output correctly in Ruby (Singly Linked List)

Trying to solve leetcode's "Add Two Numbers" problem in Ruby (https://leetcode.com/problems/add-two-numbers/). I know I have not solved the problem at all, just trying to make sure I can get my output in the correct "ListNode" format first. The ListNode I'm trying to add to keeps writing over itself because it's in the while loop but I have been working on this forever and cannot figure out how to get the output the way that leetcode wants it.
Any help is appreciated!
Here's my code:
# class ListNode
# attr_accessor :val, :next
# def initialize(val = 0)
# #val = val
# #next = nil
# end
# end
# #param {ListNode} l1
# #param {ListNode} l2
# #return {ListNode}
def add_two_numbers(l1, l2)
current_output = head = ListNode.new()
while l1.next != nil
sum = l1.val + l2.val
if current_output.next != nil
current_output = current_output.next
else
current_output.next = ListNode.new(sum)
current_output.next = current_output.next.next
end
l1.val = l1.next.val
l1.next = l1.next.next
l2.val = l2.next.val
l2.next = l2.next.next
end
last_sum = l1.val + l2.val
#current_output.next = ListNode.new(last_sum)
return current_output
end
Note: It requires that the output be a ListNode object so I can't created my own LinkedList class
Classic solution
def add_two_numbers(l1, l2)
head = ListNode.new
carry = 0
curr = head
until l1.nil? && l2.nil? && carry.zero?
v1 = l1&.val || 0
v2 = l2&.val || 0
carry, digit = (v1 + v2 + carry).divmod(10)
curr.next = ListNode.new(digit)
curr = curr.next
l1 = l1&.next
l2 = l2&.next
end
head.next
end
Note that l1 and l2 may have different lengths, so you should end the loop when both nodes become nil.
In case you don't know the syntax obj&.mthd, it's called "safe navigation", which means if obj is nil, return nil immediately without calling mthd on it. If obj is not nil, return whatever obj.mthd returns.
Cheating
You can work out the integer each list represents, add them together, and build the result list based on the sum.
# Monkey-patch ListNode
# to make a list enumerable,
# so that we can call `reduce` on it.
ListNode.class_eval do
include Enumerable
def each(&block)
return enum_for(:each) unless block
block.(#val)
#next.each(&block) if #next
end
end
def add_two_numbers(l1, l2)
n1 = l1.reduce(""){|s, n| "#{n}#{s}"}.to_i
n2 = l2.reduce(""){|s, n| "#{n}#{s}"}.to_i
head = ListNode.new
(n1 + n2).digits.reduce(head) do |prev_node, digit|
ListNode.new(digit).tap{|node| prev_node.next = node}
end
head.next
end
here is a code that sums two linked lists, then I will break it down so you can take part of it and use them, however it is not well tested as I just wrote it now after hacking into this blog post and making little edits on it:
class Node
attr_accessor :value, :next
def initialize(value, next_node)
#value = value
#next = next_node
end
end
class LinkedList
include Enumerable
def initialize
#head = nil
end
def add_to_list(value)
return #head = Node.new(value, nil) unless #head
current_node = #head
while current_node.next != nil
current_node = current_node.next
end
current_node.next = Node.new(value, nil)
end
def each
current = #head
while current
yield current.value
current = current.next
end
end
def to_i
self.reduce(""){ |s, l| "#{l}#{s}" }.to_i
end
end
list1 = LinkedList.new
list2 = LinkedList.new
sum = LinkedList.new
list1.add_to_list(2) # => #<Node:0x000055951cb54940 #value=2, #next=nil>
list1.add_to_list(4) # => #<Node:0x000055951cb545f8 #value=4, #next=nil>
list1.add_to_list(3) # => #<Node:0x000055951cb543a0 #value=3, #next=nil>
list2.add_to_list(5) # => #<Node:0x000055951cb54170 #value=5, #next=nil>
list2.add_to_list(6) # => #<Node:0x000055951cb7bf40 #value=6, #next=nil>
list2.add_to_list(4) # => #<Node:0x000055951cb7bd10 #value=4, #next=nil>
result = list1.to_i + list2.to_i # => 807
result.digits.each do |i|
sum.add_to_list(i)
end
puts list1.to_i # => nil
puts list2.to_i # => nil
puts sum.to_i # => nil
# >> 342
# >> 465
# >> 807
in the code above the following is a definition of a node of the linked list:
class Node
attr_accessor :value, :next
def initialize(value, next_node)
#value = value
#next = next_node
end
end
the node has a value attribute and a pointer to the node that comes after it in the linked list.
lets break down the linked list which has only two methods in it in this case:
the fist one is add_to_list:
def add_to_list(value)
return #head = Node.new(value, nil) unless #head
current_node = #head
while current_node.next != nil
current_node = current_node.next
end
current_node.next = Node.new(value, nil)
end
it takes an integer as a value then creates a node for it in the linked-list.
the second method is to_i which converts the linked list backward to an integer so later we can do list1.to_i + list2.to_i which gives us the sum of the two lists:
def each
current = #head
while current
yield current.value
current = current.next
end
end
def to_i
self.reduce(""){ |s, l| "#{l}#{s}" }.to_i
end
now lets come to the code that makes the actual calculation:
here is the initialization of list1, list2, and the sum lists:
list1 = LinkedList.new
list2 = LinkedList.new
sum = LinkedList.new
list1.add_to_list(2) # => #<Node:0x000055951cb54940 #value=2, #next=nil>
list1.add_to_list(4) # => #<Node:0x000055951cb545f8 #value=4, #next=nil>
list1.add_to_list(3) # => #<Node:0x000055951cb543a0 #value=3, #next=nil>
list2.add_to_list(5) # => #<Node:0x000055951cb54170 #value=5, #next=nil>
list2.add_to_list(6) # => #<Node:0x000055951cb7bf40 #value=6, #next=nil>
list2.add_to_list(4) # => #<Node:0x000055951cb7bd10 #value=4, #next=nil>
and here is doing the actual sum of both list1, and list2:
result = list1.to_i + list2.to_i # => 807
here is the conversion of the result integer value to a linked list:
result.digits.each do |i|
sum.add_to_list(i)
end
and here is the content of list1, list2, and sum variables printed out:
puts list1.to_i # => nil
puts list2.to_i # => nil
puts sum.to_i # => nil
# >> 342
# >> 465
# >> 807
so in your add_two_numbers method of the problem all what you want is to convert the two linked lists into integers in the proper way then make the sum of them, after then convert the resulting integer into a linked list which will be returned as the final solution, and make sure to run enough test cases and test the corner cases.

Ruby block works with { } but not with do...end

I was trying to implement a bubble sort method that takes a block and returns the array sorted in ascending order.
For some reason that I can't understand I get the right result when I use { } but I get the error 'no block given' when I use do...end.
Here's the code:
def bubble_sort_by(arr)
return arr if arr.size == 1
swapped = true
while swapped
swapped = false
(0...arr.size - 1).each do |index|
block_result = yield(arr[index], arr[index + 1])
# binding.pry
if block_result >= 1
arr[index], arr[index + 1] = arr[index + 1], arr[index]
swapped = true
# binding.pry
end
end
end
arr
end
p bubble_sort_by(["hi","hello","heys"]) do |left,right|
left.length - right.length
end
#the code returns ["hi", "heys", "hello"] when the block is passed with { }
Any help will be most appreciated.
Precedence matters.
{} has nearly the topmost precedence and is executed before function application (before p() call.)
do end OTOH has nearly the lowest precedence and is executed after function application (after p() call.)
Put parentheses to avoid ambiguity:
p(bubble_sort_by(["hi","hello","heys"]) do |left,right|
left.length - right.length
end)
In your original example, the order of execution was as following:
p(bubble_sort_by(["hi","hello","heys"])) do ... end
Basically, you have been calling p with a parameter and a block.

Sum values recursively in one line

I am pretty sure that it can be done in one line using things like map, sum etc. I cannot figure out how exactly, because I just started learning ruby. Could someone help? Thanks
class Something < ApplicationRecord
def function
res = items.count
items.each do |i|
res += i.function
end
res
end
I'm not sure why you need to do it recursively and in one line, but you can try something like this:
edit:
def add(arr)
return 0 if arr.length == 0
# if the arr argument is an empty array, return 0.
arr[0] + add(arr[1..-1])
# add the first element of the array to the result of calling add
# on the array minus the first element.
end
If you just want to sum an array as concisely as possible, all you need to do is [1, 2, 3].sum or [1,2,3,4].reduce(&:+). No recursion needed.
The straightforward oneliner equivalent to yours:
def function
items.count + items.sum(&:function)
end
Demo (testing it alongside your original):
class Something
attr_accessor :items
def initialize(items = [])
self.items = items
end
def function
res = items.count
items.each do |i|
res += i.function
end
res
end
def function2
items.count + items.sum(&:function2)
end
end
root = Something.new([
Something.new,
Something.new([
Something.new,
Something.new([
Something.new,
Something.new([
Something.new
])
])
])
])
puts root.function
puts root.function2
Prints:
7
7
Another way:
def function
items.sum { |i| 1 + i.function }
end
By the way, you count all items except for the root item. Is that intentional?
You could count all including the root with this:
def function
1 + items.sum(&:function)
end
Not in one line but this is how you can do this recursively.
def add_array(arr)
return arr.first if arr.length == 1
return nil if arr.length < 1
arr.pop + add_arr(arr)
end

Check if two linked lists are equal in Ruby?

I have the following implementation of a linked list in Ruby:
class Node
attr_accessor :data, :next
def initialize(data = nil)
#data = data
#next = nil
end
end
class LinkedList
def initialize(items)
#head = Node.new(items.shift)
items.inject(#head) { |last, data| #tail = last.next = Node.new(data) }
end
def iterate
return nil if #head.nil?
entry = #head
until entry.nil?
yield entry
entry = entry.next
end
end
def equal?(other_list)
#How do I check if all the data for all the elements in one list are the same in the other one?
end
end
I have tried using the .iterate like this:
def equals?(other_list)
other_list.iterate do |ol|
self.iterate do |sl|
if ol.data != sl.data
return false
end
end
end
return true
end
But this is doing a nested approach. I fail to see how to do it.
You can't do it easily with the methods you have defined currently, as there is no way to access a single next element. Also, it would be extremely useful if you implemented each instead of iterate, which then gives you the whole power of the Enumerable mixin.
class LinkedList
include Enumerable # THIS allows you to use `zip` :)
class Node # THIS because you didn't give us your Node
attr_accessor :next, :value
def initialize(value)
#value = value
#next = nil
end
end
def initialize(items)
#head = Node.new(items.shift)
items.inject(#head) { |last, data| #tail = last.next = Node.new(data) }
end
def each
return enum_for(__method__) unless block_given? # THIS allows block or blockless calls
return if #head.nil?
entry = #head
until entry.nil?
yield entry.value # THIS yields node values instead of nodes
entry = entry.next
end
end
def ==(other_list)
# and finally THIS - get pairs from self and other, and make sure all are equal
zip(other_list).all? { |a, b| a == b }
end
end
a = LinkedList.new([1, 2, 3])
b = LinkedList.new([1, 2, 3])
c = LinkedList.new([1, 2])
puts a == b # => true
puts a == c # => false
EDIT: I missed this on the first run through: equal? is supposed to be referential identity, i.e. two variables are equal? if they contain the reference to the same object. You should not redefine that method, even though it is possible. Rather, == is the general common-language meaning of "equal" as in "having the same value", so I changed it to that.
I think there is something wrong with your initialize method in LinkedList, regardless could this be what you need
...
def equal?(other_list)
other_index = 0
cur_index = 0
hash = Hash.new
other_list.iterate do |ol|
hash[ol.data.data] = other_index
other_index += 1
end
self.iterate do |node|
return false if hash[node.data.data] != cur_index
return false if !hash.has_key?(node.data.data)
cur_index += 1
end
return true
end
...
Assuming this is how you use your code
a = Node.new(1)
b = Node.new(2)
c = Node.new(3)
listA = [a,b,c]
aa = Node.new(1)
bb = Node.new(2)
cc = Node.new(3)
listB = [aa,bb,cc]
linkA = LinkedList.new(listA)
linkB = LinkedList.new(listB)
puts linkA.equal?(linkB)

Nil when calling a method on the variable, but not nil when calling just the variable

Don't understand why #nums.pop won't work in the value method. It seems to tell me that it can't do that for nil, but if I just say #nums, it shows that there is indeed something in the array. So then why can't I pop it out?
class RPNCalculator
def initialize
#value = value
nums ||= []
#nums = nums
end
def push(num)
#nums << num
end
def plus
if #nums[-2] == nil || #nums[-1] == nil
raise "calculator is empty"
else
#value = #nums.pop + #nums.pop
#nums.push(#value)
end
end
def minus
if #nums[-2] == nil || #nums[-1] == nil
raise "calculator is empty"
else
#value = #nums[-2] - #nums[-1]
#nums.pop(2)
#nums.push(#value)
end
end
def divide
if #nums[-2] == nil || #nums[-1] == nil
raise "calculator is empty"
else
#value = #nums[-2].to_f / #nums[-1].to_f
#nums.pop(2)
#nums.push(#value)
end
end
def times
if #nums[-2] == nil || #nums[-1] == nil
raise "calculator is empty"
else
#value = #nums.pop.to_f * #nums.pop.to_f
#nums.push(#value)
end
end
def value
#nums #Don't understand why #nums.pop won't work here
end
def tokens(str)
str.split(" ").map { |char| (char.match(/\d/) ? char.to_i : char.to_sym)}
end
def evaluate(str)
tokens(str).each do |x|
if x == ":-"
minus
elsif x == ":+"
plus
elsif x == ":/"
divide
elsif x ==":*"
times
else
push(x)
end
end
value
end
end
Error relates to the following part of a spec:
it "adds two numbers" do
calculator.push(2)
calculator.push(3)
calculator.plus
calculator.value.should == 5
end
Error says either:
Failure/Error: calculator.value.should == 5
expected: 5
got: [5] <using ==>
OR if .pop is used
Failure/Error: #calculator = RPNCalculator.new
NoMethodError:
undefined method 'pop' for nil:NilClass
Your initialize method assigning #value = value calls the function at def value which returns #nums which has not yet been created in initialize since #nums is created afterwards with nums ||= []; #nums = nums therefore it's nil. This is why .pop won't work.
You've created #nums as an array with nums ||= [] and you're using it with push and pop so why are you checking for the value with value.should == 5 (Integer) when calling value returns an (Array). You would need to write it like value.first.should == 5 or value[0].should == 5 ... otherwise you should change value to return just the element you want
def value
#nums.pop # or #nums[0], or #nums.first or #nums.last however you plan on using it
end
The problem is #value = value in your initialize method. Fix that then you can add the .pop in value.
EDIT
Also your evaluation is calling methods before you've populated #nums with the values. Then the methods "raise" errors. You can't call minus after only one value has been pushed to #nums.
Here's how I would do the flow for splitting the string
# Multiplication and Division need to happen before addition and subtraction
mylist = "1+3*7".split(/([+|-])/)
=> ["1", "+", "3*7"]
# Compute multiplication and division
mylist = mylist.map {|x| !!(x =~ /[*|\/]/) ? eval(x) : x }
=> ["1", "+", 21]
# Do the rest of the addition
eval mylist.join
=> 22
I realize this isn't exactly how you're going about solving this... but I think splitting by order of mathematical sequence will be the right way to go. So first evaluate everything between (), then only multiplication and division, then all addition and subtraction.
EDIT I just looked into what a RPN Calculator is. So don't mind my splitting recommendation as it doesn't apply.

Resources