Check if two linked lists are equal in Ruby? - 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)

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.

Passing the return value from my negmax method

I've been working on this for a few days, at least. Testing seems to show the correct value is being returned. My problem is being able to grab the best_move value and have it print out. I set up the suggested_move method and try to use return suggested_move(best_move) but it triggers the method for every level back up the tree. Also it returns the wrong value, which I'm guessing is because it's stopping before depth is back to 0.
In my minimax I had a similar setup the difference being the depth was incremented (not decremented) on successive calls. Point being I was able to say if depth == 0 p best_move. So I'm scratching my head because using that same conditional I get a nil class error in this code.
#board = ["X","O","O","X","X","","","O",""]
def available_spaces
#board.map.with_index {|a, i| a == "" ? i+1 : nil}.compact
end
def suggested_move(move)
p "Suggested move: #{move}"
end
def full?
#board.all?{|token| token == "X" || token == "O"}
end
def suggested_move(move)
p "Move: #{move}"
end
def bestmove(board, depth=0, best_score = {})
return 0 if full?
return 1 if won?
best = -Float::INFINITY
available_spaces.each do |space|
#board[space-1] = current_player
best_score[space] = -bestmove(#board, depth-1, {})
#board[space-1] = ""
end
p best_score
if best_score.max_by {|key,value| value }[1] > best
best = best_score.max_by {|key,value| value }[1]
best_move = best_score.max_by {|key,value| value }[0]
end
return best_move
end
bestmove(#board)

Ruby: Modify a Range

I'm trying to add a method to the Range class. The goal is to check if an integer is is included in the range and to include it if it isn't. It would be useful to store in a Range some minimum and maximum values.
So I was thinking of the following:
class Range
def include!(n)
if n < self.begin
self = n..self.end
elsif n > self.end
self = self.begin..n
end
end
end
r = Range.new(500, 500)
100.times do
r.include!(rand(1000))
end
But I get a Can't change the value of self error.
Would this be the only solution:
class Range
def include(n)
if n < self.begin
n..self.end
elsif n > self.end
self.begin..n
else
self
end
end
end
r = Range.new(500, 500)
100.times do
r = r.include(rand(1000))
end
Ranges themselves are immutable, you can't change their properties after they are created. However, it's still possible to achieve what you want by creating new ranges instead of modifying existing ones, as you discovered. I'd probably do it like this:
module RangeAdder
def +(value)
return self if value.nil?
return self + value.min + value.max if value.is_a? Range
return value.reduce(self, :+) if value.is_a? Enumerable
new_begin = [self.begin, value].min
new_end = [self.end, value].max
new_exclude_end = value > self.end ? false : self.exclude_end?
Range.new(new_begin, new_end, new_exclude_end)
end
end
class Range
include RangeAdder
end
Then:
r = 500..500
r += Array.new(100) { rand(1000) }
#=> 15..982
Or if all you really want to do is get the minimum and maximum values from an array, you can do that with:
a = Array.new(100) { rand(1000) }
r = Range.new(*a.minmax)
#=> 11..996

How to handle combination []+= for auto-vivifying hash in Ruby?

In order to implement auto-vivification of Ruby hash, one can employ the following class
class AutoHash < Hash
def initialize(*args)
super()
#update, #update_index = args[0][:update], args[0][:update_key] unless
args.empty?
end
def [](k)
if self.has_key?k
super(k)
else
AutoHash.new(:update => self, :update_key => k)
end
end
def []=(k, v)
#update[#update_index] = self if #update and #update_index
super
end
def few(n=0)
Array.new(n) { AutoHash.new }
end
end
This class allows to do the following things
a = AutoHash.new
a[:a][:b] = 1
p a[:c] # => {} # key :c has not been created
p a # => {:a=>{:b=>1}} # note, that it does not have key :c
a,b,c = AutoHash.new.few 3
b[:d] = 1
p [a,b,c] # => [{}, {:d=>1}, {}] # hashes are independent
There is a bit more advanced definition of this class proposed by Joshua, which is a bit hard for me to understand.
Problem
There is one situation, where I think the new class can be improved. The following code fails with the error message NoMethodError: undefined method '+' for {}:AutoHash
a = AutoHash.new
5.times { a[:sum] += 10 }
What would you do to handle it? Can one define []+= operator?
Related questions
Is auto-initialization of multi-dimensional hash array possible in Ruby, as it is in PHP?
Multiple initialization of auto-vivifying hashes using a new operator in Ruby
ruby hash initialization r
still open: How to create an operator for deep copy/cloning of objects in Ruby?
There is no way to define a []+= method in ruby. What happens when you type
x[y] += z
is
x[y] = x[y] + z
so both the [] and []= methods are called on x (and + is called on x[y], which in this case is an AutoHash). I think that the best way to handle this problem would be to define a + method on AutoHash, which will just return it's argument. This will make AutoHash.new[:x] += y work for just about any type of y, because the "empty" version of y.class ('' for strings, 0 for numbers, ...) plus y will almost always equal y.
class AutoHash
def +(x); x; end
end
Adding that method will make both of these work:
# Numbers:
a = AutoHash.new
5.times { a[:sum] += 10 }
a[:sum] #=> 50
# Strings:
a = AutoHash.new
5.times { a[:sum] += 'a string ' }
a[:sum] #=> "a string a string a string a string a string "
And by the way, here is a cleaner version of your code:
class AutoHash < Hash
def initialize(args={})
super
#update, #update_index = args[:update], args[:update_key]
end
def [](k)
if has_key? k
super(k)
else
AutoHash.new :update => self, :update_key => k
end
end
def []=(k, v)
#update[#update_index] = self if #update and #update_index
super
end
def +(x); x; end
def self.few(n)
Array.new(n) { AutoHash.new }
end
end
:)
What I think you want is this:
hash = Hash.new { |h, k| h[k] = 0 }
hash['foo'] += 3
# => 3
That will return 3, then 6, etc. without an error, because the the new value is default assigned 0.
require 'xkeys' # on rubygems.org
a = {}.extend XKeys::Hash
a[:a, :b] = 1
p a[:c] # => nil (key :c has not been created)
p a # => { :a => { :b => 1 } }
a.clear
5.times { a[:sum, :else => 0] += 10 }
p a # => { :sum => 50 }

Recursively merge multidimensional arrays, hashes and symbols

I need a chunk of Ruby code to combine an array of contents like such:
[{:dim_location=>[{:dim_city=>:dim_state}]},
:dim_marital_status,
{:dim_location=>[:dim_zip, :dim_business]}]
into:
[{:dim_location => [:dim_business, {:dim_city=>:dim_state}, :dim_zip]},
:dim_marital_status]
It needs to support an arbitrary level of depth, though the depth will rarely be beyond 8 levels deep.
Revised after comment:
source = [{:dim_location=>[{:dim_city=>:dim_state}]}, :dim_marital_status, {:dim_location=>[:dim_zip, :dim_business]}]
expected = [{:dim_location => [:dim_business, {:dim_city=>:dim_state}, :dim_zip]}, :dim_marital_status]
source2 = [{:dim_location=>{:dim_city=>:dim_state}}, {:dim_location=>:dim_city}]
def merge_dim_locations(array)
return array unless array.is_a?(Array)
values = array.dup
dim_locations = values.select {|x| x.is_a?(Hash) && x.has_key?(:dim_location)}
old_index = values.index(dim_locations[0]) unless dim_locations.empty?
merged = dim_locations.inject({}) do |memo, obj|
values.delete(obj)
x = merge_dim_locations(obj[:dim_location])
if x.is_a?(Array)
memo[:dim_location] = (memo[:dim_location] || []) + x
else
memo[:dim_location] ||= []
memo[:dim_location] << x
end
memo
end
unless merged.empty?
values.insert(old_index, merged)
end
values
end
puts "source1:"
puts source.inspect
puts "result1:"
puts merge_dim_locations(source).inspect
puts "expected1:"
puts expected.inspect
puts "\nsource2:"
puts source2.inspect
puts "result2:"
puts merge_dim_locations(source2).inspect
I don't think there's enough detail in your question to give you a complete answer, but this might get you started:
class Hash
def recursive_merge!(other)
other.keys.each do |k|
if self[k].is_a?(Array) && other[k].is_a?(Array)
self[k] += other[k]
elsif self[k].is_a?(Hash) && other[k].is_a?(Hash)
self[k].recursive_merge!(other[k])
else
self[k] = other[k]
end
end
self
end
end

Resources