Ruby Reference & Value pass by - ruby

I know a lot of similar questions have been asked. I've read them, and still don't understand WHY my code does what it does. It s only for training, and I've implement a simple LinkedList (single link) and I wanted to implement the merge of two such sorted list. Here is the code
#!/usr/bin/ruby
#
module LinkedList
class Node
attr_accessor :next,:data
def to_s
s = #data.to_s + " -> "
s += #next.to_s if #next
s
end
end
end
def append tail, node
tail.next = node
tail = node
node = node.next
end
def merge_lists2 list1, list2
tail = LinkedList::Node.new
while(list1 && list2)
list1.data <= list2.data ? list1 = append(tail,list1) : list2 = append(tail,list2)
puts list1
puts list2
puts tail
puts "#######################################################"
STDIN.gets
end
if list1
tail.next = list1
elsif list2
tail.next = list2
end
tail.next
end
def generateList times = 3,factor = 1
list = LinkedList::Node.new
list.data = 0
curr = list
(1..times).each do |i|
curr.next = LinkedList::Node.new
curr = curr.next
curr.data = i*factor
end
list
end
def main
l1 = generateList 4,2
l2 = generateList 5,1.5
puts l1
puts l2
l3 = merge_lists2 l1,l2
puts l3
end
The code following is my "older" version :
def append tail, node
tail.next = node
tail = node
node = node.next
end
def merge_lists2 list1, list2
tail = LinkedList::Node.new
while(list1 && list2)
list1.data <= list2.data ? append(tail,list1) : append(tail,list2)
In the older version, it was running in a infinite loop because list1 and list2 were never updated, thus the while loop was always going on. They were never updated because of the list1 & list2 variable were assigned to different object in the append function, thus when returning from the function, list1 and list2 were "taking back" on their original reference.
But the "tail" reference is updated !! You can see it by running the code, you will see that tail is always the "tail" of the new merged list, and not the "head" of the new list. I dont understand why because tail is ALSO referenced to a new object in append, so when returning from the function, "tail" should still be the "head" (lol that's crazy )
Thank you ...

The problem with Ruby is it hides a lot of things from you. Objects are passed in as what appear to be references, but are actually pointers in a clever disguise. When you "de-reference" a pointer you get to manipulate the original data, not unlike a reference. Unlike C++ where this is made explicit, Ruby doesn't go out of its way to remind you this is the case.
So what this means is arguments to methods are simply variables that behave like pointers to objects. Changing them to other values does not affect the original. Calling methods on them or changing properties does affect the original, they've been de-referenced.
There's a lot of problems with your implementation here. For one, methods like append should be part of the Node class:
class Node
def append(list)
node = #data
while (node)
if (node.next)
node = node.next
else
node.next = list
return self
end
end
end
end
So long as you don't have a circular list, that should work. Notice that the list value is never modified, it's simply integrated.
Note that this append method works for both individual nodes (one element lists) and longer lists composed of multiple nodes. Generally in programming you try to avoid having exceptional cases to handle, so this minimizes the code you need to write and get working properly.

Related

My Code Searches a Tree for a Target, but is this Recursive?

I am attempting to search a simple tree to find a target value. My instructions are to use recursion. I understand that recursion means (in part) that the method is called from within itself. In that sense the following code succeeds. However, I also understand (I think) that recursion requires setting up an inquiry that cannot be resolved until the base case is reached, at which time the answer is passed back in the chain and each unresolved inquiry can be resolved. My code does not really do that (I think). I need a higher power to show me (and hopefully others) the way.
class Tree
attr_accessor :payload, :children
def initialize(payload, children)
#payload = payload
#children = children
end
def self.test (node, target)
if node.payload == target
print "Bingo!"
else
print node.payload
end
node.children.each do |child|
Tree.test(child, target)
end
end
end
# The "Leafs" of a tree, elements that have no children
deep_fifth_node = Tree.new(5, [])
eleventh_node = Tree.new(11, [])
fourth_node = Tree.new(4, [])
# The "Branches" of the tree
ninth_node = Tree.new(9, [fourth_node])
sixth_node = Tree.new(6, [deep_fifth_node, eleventh_node])
seventh_node = Tree.new(7, [sixth_node])
shallow_fifth_node = Tree.new(5, [ninth_node])
# The "Trunk" of the tree
trunk = Tree.new(2, [seventh_node, shallow_fifth_node])
Tree.test(trunk, 5)
Assuming your function calls itself (and yours appears to), you're using recursion. See https://softwareengineering.stackexchange.com/questions/25052/in-plain-english-what-is-recursion for a good discussion on recursion.
To prevent infinite recursion, you'll want a base case that makes sure that you do eventually unwind everything completely, rather than simply continuing to call your function forever, and quite often that is when you're fully complete with whatever computation you're running, but it doesn't necessarily mean you couldn't find what you're looking for (in the case of a search) before you reach the base case.
Yes, your function is using recursion: It calls itself.
Here is a proposal for your method:
def find_nodes_with_payload?(target, result = [])
if payload == target
result << self
end
children.each do |child|
child.find_nodes_with_payload?(target, result)
end
accu
end
The method will collect all the nodes in a (sub)-tree containing a specific target value. Does solve your problem?
I modified your original code in following ways:
Made it an instance method and removed the 'node' argument
Renamed it from 'test' to something more descriptive, IMHO
added an array which collects all the nodes that contain the payload
changed the logic to: do nothing but recursively call the method again for all the children if the condition does not match
You can make it simple.
def search(tree, target)
trav = ->(node) { node.val == target ? puts("Bingo") : node.leaves.each(&trav) }
trav[tree]
end
Tree creation can also be simplified.
Node = Struct.new(:val, :leaves)
add = ->(tree) { tree ? tree.map {|k,v| Node.new(k, add[v])} : [] }
So we can recursively create tree and find value.
sample_tree = {2 => {7 => {6 => {4=>{}, 11=>{}}}, 5=> {9 => {}, 4=>{}}}}
tree = add[sample_tree]
search(tree.first, 5)

How to reverse a LinkedList in place

Update: I'm realizing now my question should be: how do I pass an argument by REFERENCE? I have a clue here: 'pass parameter by reference' in Ruby? but I don't nkow if it's even possible. Might be worth closing this question in fact.
In reference to this previous question: How to reverse a linked list in Ruby
I'm a bit confused why the list isn't reversed in place.
So my expectation would be that:
print_values(node3)
Would initially give:
12 -> 99 -> 37 -> nil
And then when I call: reverse_list(node3)
I would expect a call to print_values(node3) to give 37 -> 99 -> 12 -> nil
However, I'm instead getting 12 -> nil
To a degree this makes sense because the object referenced by node3 still has a value of 12 and has a next_node of nil, but is there a way to reverse the list completely in place in Ruby?
There seems to be something here about mutability w/r/t ruby that I'm not quite grasping. It's as though with every new addition to the memory stack/function call we get new objects? Some clarification here would be much appreciated.
I've also creatd my own method to try to get the functionality working in place:
def reverse_list(list, previous=nil)
rest_of_list = list.next_node
print "rest of list: "
print_values(rest_of_list)
list.next_node = previous
previous = list
print "new previous: "
print_values(previous)
list = rest_of_list
print "new list: "
print_values(list)
if list.nil?
print "list now nil\n"
list = previous
print "updated list: "
print_values(list)
return list
else
reverse_list(list, previous)
end
end
In answer to your updated question:
Yes you will have to reverse the values of the list, instead of the pointers.
To do this AFAIK you have to first build a new reversed list, and then copy the reversed values back into the original list.
I have updated the original code to be more ruby-ish (i.e. the methods are part of the list class, and the "!" suffix is used to indicate the method will modify the object (rather than just return a new value.)
<script type="text/ruby">
def print(s)
s = s.gsub("\n", "<br/>").gsub(" ", " ")
Element['#output'].html = Element['#output'].html + s
end
class LinkedListNode
attr_accessor :value, :next_node
def initialize(value, next_node=nil)
#value = value
#next_node = next_node
end
def reverse_list(reversed=nil)
if next_node
next_node.reverse_list(LinkedListNode.new(value, reversed))
else
LinkedListNode.new(value, reversed)
end
end
def reverse_list!(list=self, reversed_list = reverse_list)
self.value = reversed_list.value
if next_node
next_node.reverse_list!(list, reversed_list.next_node)
else
list
end
end
def print_values
print "[#{object_id}]#{value} --> "
if next_node.nil?
print "nil\n"
else
next_node.print_values
end
end
end
node1 = LinkedListNode.new(37)
node2 = LinkedListNode.new(99, node1)
node3 = LinkedListNode.new(12, node2)
print "original list: "
node3.print_values
print "reversed list: "
node3.reverse_list.print_values
print "reversed in place: "
node3.reverse_list!
node3.print_values
</script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/reactrb/reactrb-express/master/reactrb-express.js"></script>
<div id="output" style="font-family: courier"></div>
There is no pass by reference in Ruby
For all but the most basic classes such as numbers, there are methods that will modify an object in place, thus accomplishing much of the functionality of call by reference.

ruby recursive loop with sub-block return design

I have a Ruby application that I'm developing that, for some reason, does not work as expected when using a recursive function that contains a block inside to return a value from a different class' function call (easier to see in the example code below). The odd thing is that when I created a minimal sample to try and find out what was going on, the sample works as expected. Example:
require 'json'
class Simple
attr_accessor :name, :children
def initialize(name,children=nil)
#name = name
#children = children
end
end
a = Simple.new('A')
b = Simple.new('B',[a])
c = Simple.new('C',[b])
d = Simple.new('D')
e = Simple.new('E',[d])
f = Simple.new('F')
g = Simple.new('G',[e,f])
foo = [c,e,g]
def looper(d)
holder = nil
d.each do |item|
# puts item.name
if item.name == 'D'
holder = Simple.new('Z',[])
elsif !item.children.nil?
holder = looper(item.children)
end
end
return holder
end
bar = looper(foo)
puts "Returned from looper: #{bar.name}"
In my actual code I ended up using the a class instance variable to get the response (which also works in the sample code). Example snippet of the function from above modified to the other pattern:
def looper(d)
holder = nil
d.each do |item|
# puts item.name
if item.name == 'D'
#holder = Simple.new('Z',[])
elsif !item.children.nil?
looper(item.children)
end
end
#holder
end
So my question is, is it good practice to use the instance variable? Any down sides to doing so since it works for my actual code whereas the first example pattern does not?
In your first piece of code, I'd expect to see a nil from your input, where in your second version you will get the object Simple.new('Z',[])
If that's your problem, it's because item g has children, the first one will set a value recusrively, but the second one will unset the value, so the second time through the loop, holder gets set to nil.
Edit: Actually my analysis of the results form the example above is wrong, because the last item in the top level list does contain the searched-for item. However, the analysis of the problem and difference in behaviour between the two solutions still holds in general.
You probably just want this:
def looper(d)
holder = nil
d.each do |item|
# puts item.name
if item.name == 'D'
holder = Simple.new('Z',[])
break
elsif !item.children.nil?
holder = looper(item.children)
break if holder
end
end
return holder
end
The break statement prevents you assigning again to holder . . .
Alternatively use Ruby internals like #first or #any? to express your search.
Assigning to instance variables as per your second example to inter-communicate between recursions is just fine, they are effectively shared state between all depths and iterations while the recursion runs. So it doesn't break recursion or Ruby per se, although you have to watch out for other kinds of unwanted interaction: For example you cannot assume an instance variable was set in a particular place during recursion, compared to current depth or loop item . . .

Modify Calling Object in Ruby

I am in the process of learning Ruby and as practice I am making a linked list class. I am in the process of writing the delete method for a doubly linked list. My question is, if I represent the list by its head node, how do I delete the head? It seems like Ruby wont allow you to assign to the self variable, so I can't change the reference of the caller to be the next node. One solution is that I can copy the key from the next node and swap references, but in general, is there a way in Ruby to change the reference of the caller?
class LinkedListNode
attr_accessor :next, :previous, :key
def initialize(key=nil, next_node=nil, previous=nil)
#next = next_node
#previous = previous
#key = key
end
def append(key=nil)
newnode = LinkedListNode.new(key)
seeker = self
while seeker.next != nil
seeker = seeker.next
end
newnode.previous = seeker
seeker.next = newnode
end
def delete(key=nil)
seeker = self
while seeker.key != key
return if seeker.next == nil
seeker = seeker.next
end
if seeker.previous != nil
if seeker.next != nil
seeker.previous.next = seeker.next
seeker.next.previous = seeker.previous
else
seeker.previous.next = nil
end
else
return self = self.next
end
return seeker = nil
end
def print
seeker = self
string = ""
while 1
if seeker.next == nil
string += seeker.key.to_s
break
else
string += seeker.key.to_s + " -> "
end
seeker = seeker.next
end
puts string
end
end
if __FILE__ == $0
ll = LinkedListNode.new(1)
ll.append(2)
ll.append(3)
ll.append(4)
ll.append(5)
ll.print
ll.delete(5)
ll.print
ll.delete(1)
ll.print
end
You can't change the which object is being pointed to by the caller (i.e. modify self), but you can manipulate the object in any way you want, as you've already thought through. The short answer is that it can't be done. You can come up with other ways to model it, but I think you're already on the right track.
You need to conceptualize a linked list differently. A LinkedListNode is a component of a LinkedList, not a LinkedList itself. Operations such as append, delete, and print should go in your LinkedList class, not your LinkedListNode class. Try starting with something like
class LinkedList
# This one-liner defines a LinkedList::Node with associated constructor
# and accessors for the three tags provided. Any tags omitted during
# construction will be initialized to nil.
Node = Struct.new(:key, :previous, :next)
attr_reader :head, :tail
def initialize
# start with no Nodes in the list
#head = #tail = nil
end
def append(key)
# Make the LinkedList tail a new node that stores the key,
# points to the prior tail as its previous reference, and
# has no next.
#tail = Node.new(key, #tail)
if #tail.previous # the prior tail was not nil
#tail.previous.next = #tail # make the prior tail point to the new one
else # if there wasn't any tail before the list was empty
#head = #tail # so the new tail Node is also the head
end
end
# ...
end

Why is this recursion NOT infinite?

My friends and I are working on some basic Ruby exercises to get a feel for the language, and we've run into an interesting behavior that we're yet unable to understand. Basically, we're creating a tree data type where there's just one class, node, which contains exactly one value and an array of zero or more nodes. We're using rspec's autospec test runner. At one point we started writing tests to disallow infinite recursion (a circular tree structure).
Here's our test:
it "breaks on a circular reference, which we will fix later" do
tree1 = Node.new 1
tree2 = Node.new 1
tree2.add_child tree1
tree1.add_child tree2
(tree1 == tree2).should be_false
end
Here's the Node class:
class Node
attr_accessor :value
attr_reader :nodes
def initialize initial_value = nil
#value = initial_value
#nodes = []
end
def add_child child
#nodes.push child
#nodes.sort! { |node1, node2| node1.value <=> node2.value }
end
def == node
return (#value == node.value) && (#nodes == node.nodes)
end
end
We expect the last line of the test to result in an infinite recursion until the stack overflows, because it should continually compare the child nodes with each other and never find a leaf node. (We're under the impression that the == operator on an array will iterate over the array and call == on each child, based on the array page of RubyDoc.) But if we throw a puts into the == method to see how often it's called, we discover that it's called exactly three times and then the test passes.
What are we missing?
Edit: Note that if we replace be_false in the test with be_true then the test fails. So it definitely thinks the arrays are not equal, it's just not recursing over them (aside from the three distinct calls to ==).
If you click on the method name of the RubyDoc you linked to, you will see the source (in C) of the Array#== method:
{
// [...]
if (RARRAY(ary1)->len != RARRAY(ary2)->len) return Qfalse;
if (rb_inspecting_p(ary1)) return Qfalse;
return rb_protect_inspect(recursive_equal, ary1, ary2);
}
This implementation (specifically the "recursive_equal") suggests that Array#== already implements the infinite recursion protection you're after.

Resources