This is a contrived example to emulate what is going on in another project. I'm sure I'm just misunderstanding some basic function of classes, but I don't know where to look to find the answer.
If I set an instance variable #empty = [] in the parent class, then I want to use the original instance variable, as well as a variation of the instance variable in a child class, I'm getting an issue where the original instance variable is no longer accessible in its original form.
class Parent
def initialize
#empty = []
end
def fill
#empty << "foo" #interestingly, changing the << to = fixes it, but that's not a possibility on my project
end
end
class Child < Parent
def initialize
super
#should_still_be_empty = #empty #trying to "make a copy" of the original
end
def show_original_variable
#should_still_be_empty
end
end
child = Child.new
child.fill #=> ["foo"], which is what it should return
child.show_original_variable #=> ["foo"], I want it to return []
UPDATE:
After playing around a little more, I noticed that this happens within the same classes, as well. Why?
class Child
def initialize
#original_empty = []
#copy_of_empty = #original_empty
end
def fill
#copy_of_empty << "foo"
end
def show_empty
#original_original_variable
end
end
child = Child.new
child.fill #=> ["foo"]
child.show_original_variable #=> ["foo"], but I want it to be empty
You question has nothing in particular to do with classes or inheritance. Rather, it deals with more basic issues related to assignment and mutation.
xs = [11,22,33]
ys = xs # Both variables hold a reference to the same data.
zs = xs.dup # But zs has a copy (at least a shallow copy).
xs << 44 # If we *mutate* xs, ys changes also.
p xs # [11, 22, 33, 44]
p ys # [11, 22, 33, 44]
p zs # [11, 22, 33]
xs = [4,5,6] # If we *assign* to xs, ys won't be affected.
p xs # [4,5,6]
p ys # [11, 22, 33, 44]
The same behaviors would be observed even if the xs array started out empty (as in your code), but it's a little easier to illustrate with data values present.
If you want #should_still_be_empty to have an independent copy of the underlying data values, you need to do something along these lines:
#should_still_be_empty = #empty.dup
Doing #copy = #original stores the reference to the original object in the #copy instance variable.
Using Object#dup will create a shallow copy of the object you're assigning and store it in the instance variable.
class Child
def initialize
#original_empty = []
#copy_of_empty = #original_empty.dup
end
def fill
#copy_of_empty << "foo"
end
def show_empty
#original_empty
end
end
child = Child.new
child.fill
#=> ["foo"]
child.show_empty
#=> []
Related
I have a hash where multiple keys (lets say 1-5) point to one object (lets call a).
Keys (6-10) points to another object(say, b).
At some point I merged "b" into "a", now i have to make sure everyone sees the same object (also merging "a" into "b" and creating two objects with same content is not an option)
Is there a way to make any reference to "b" just redirect to "a" (keys 1-10 now point to object a) without manually updating keys 6-10 ?
You can't switch out one object for another unless you have some kind of a wrapper. Unless performance matters a lot, the easiest wrappers to use are proxy objects, because you don't need to unwrap them: they transparently behave exactly like the wrapped object.
class ProxyObject
# thanks to https://alisdair.mcdiarmid.org/invisible-proxies-with-ruby/
instance_methods.each do |m|
undef_method(m) unless m =~ /(^__|^nil\?$|^send$|^object_id$)/
end
attr_accessor :target
def initialize(target)
#target = target
end
def respond_to?(symbol, include_priv=false)
#target.respond_to?(symbol, include_priv)
end
private def method_missing(method, *args, &block)
#target.send(method, *args, &block)
end
end
a = 1
b = 10
a_proxy = ProxyObject.new(a)
b_proxy = ProxyObject.new(b)
a_proxy.class # verify how well they masquerade
# => Integer
hash = 10.times.map { |i| [i + 1, i < 5 ? a_proxy : b_proxy] }.to_h
# => {1=>1, 2=>1, 3=>1, 4=>1, 5=>1, 6=>10, 7=>10, 8=>10, 9=>10, 10=>10}
hash.values.sum() # confirm it behaves exactly like a number
# => 55
b_proxy.target = a_proxy.target # switch reference
hash
# => {1=>1, 2=>1, 3=>1, 4=>1, 5=>1, 6=>1, 7=>1, 8=>1, 9=>1, 10=>1}
hash.values.sum() # confirm the reference is changed
# => 10
I think I found an answer but I still have to code it
instead of the hash having an object, it will contain an array
array[0] will originally point to itself, array[1] will be the actual object
so this is the setup: hash1-5 points to arr1, hash6-10 points to arr2, arr1[0] points to itself and arr1[0]
after merging arr2[1] (b in the original question) into arr1[1] (a into the original question), I will update arr2[0] to point to arr1.
finally, after every key retrieval I will run something along the lines of
test = hash[6]
while test[0] != test
test = test[0]
end
I'm a ruby newbie, learning to code. I wanted to understand how some of the methods available from the Enumerable module work. So I'm reimplementing them. One challenge was to implement them using recursion. However, I'm running into a problem when trying to implement the Enumerable#Map method using recursion.
This is my code:
class Array
def mymap_recursive(&block)
copy_of_array = dup
new_array = []
return new_array if copy_of_array.empty?
value = copy_of_array.shift
new_array << yield(value)
copy_of_array.mymap_recursive(&block)
end
end
I tried to figure out why it wasn't working so I put
puts "#{new_array}"
at the end of the method. Then in Sublime Text, I did
arr = [2,2,5,5,10]
arr.mymap_recursive {|n| n * n}
After pressing cmd+b, the output I got was:
[100]
[25]
[25]
[4]
[4]
I cannot figure out why its not returning one array with all the values.
Thanks for your help!
What is happening in your code is every time you call mymap_recursive(&block) the new_array is being lost. To solve this you must have a way to maintain the new array that is being built recursively. A simple change to your code is including new_array = [] in your method definition, then passing new array each time. Here would be the code with my changes in place:
class Array
def mymap_recursive(new_array = [], &block)
copy_of_array = self.dup
return new_array if copy_of_array.empty?
value = copy_of_array.shift
new_array << yield(value)
copy_of_array.mymap_recursive(new_array, &block)
end
end
Then when you call
arr = [2,2,5,5,10]
p arr.mymap_recursive {|n| n * n}
#returns
#[4, 4, 25, 25, 100]
If you have any questions over this syntax or anything let me know and I will try my best to explain it!
Another solution which doesn't change the method signature and doesn't mutate any data:
class Array
def mymap_recursive(&block)
if empty?
[]
else
[block.call(first)] + drop(1).mymap_recursive(&block)
end
end
end
For the class NumberSet, I have to define the [] method so that it takes one argument, which it uses as a filter to select members of the set and returns a new set containing those elements.
For example, I have
Filter.new { |number| number.even? }
and
SignFilter.new(:non_negative)
which are classes that I must construct.
I also have to define the & and | operators so that they work with the filters. Something along the lines of
numbers[SignFilter.new(:non_negative) & Filter.new { |number| number.even? }]
The class so far is:
class NumberSet
include Enumerable
def initialize
#arr=[]
end
def each (&block)
#arr.each do |member|
block.call (member)
end
end
def << number
#arr<<number unless #arr.include?(number)
end
end
For Filter I think something like works:
class Filter
def initialize
yield
end
end
My biggest problem is the [], $and | parts, which I have no idea how to do.
What I want to accomplish is :
numbers = NumberSet.new
[-3, -2, -1, 0, 1, 2, 3, 4, 5].each do |number|
numbers << number
end
numbers[SignFilter.new(:non_negative) & Filter.new { |number| number.even?}].to_a
#=>[0, 2, 4]
I think this should do it.
Code
SignFilter class
class SignFilter
def initialize(sign)
#sign = sign
end
def filter
case #sign
when :negative
-> i { i < 0 }
when :positive
-> i { i > 0 }
when :non_negative
-> i { i >= 0 }
when :non_positive
-> i { i <= 0 }
when :zero
-> i { i.zero? }
end
end
end
Filter class
class Filter
attr_reader :filter
def initialize &filter
#filter = filter
end
end
NumberSet class
class NumberSet
def initialize arr
#arr = arr
end
def process(op, sf, f)
sign_filter = sf.filter
filter = f.filter
#arr.send(op).each { |e| sign_filter.call(e) }
.send(op).each { |e| filter.call(e) }
end
end
Examples
sf = SignFilter.new :negative
f = Filter.new { |number| number.even? }
ns = NumberSet.new [-3, -2, -1, 0, 1, 2, 3, 4, 5]
ns.process(:reject, sf, f)
#=> [1, 3, 5]
sf = SignFilter.new :non_negative
f = Filter.new { |number| number % 3 == 0 }
ns = NumberSet.new [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6]
ns.process(:select, sf, f)
#=> [0, 3, 6]
Explanation
Blocks are not objects, so you can't pass them around. They can be converted to procs, however, which are objects (instances of the class Proc), and therefore can be passed. You will need to understand procs (and lambdas, which are a type of proc). Here is a good explanation. (Aside: one thing that's a little confusing about procs is the multitude of ways they can be invoked. For example, if p -> i { 3*i }, p.call(2), p.yield(2), p[2] and p.(2) all return the value 6.)
Here is what is happening:
An instance sf of the SignFilter class is created by passing the symbol denoting the signs of the elements of the array that are to be selected or rejected (:negative, :non_negative and so on). The symbol is saved in an instance variable #sign.
The SignFilter class has a method filter which returns a lambda based on the value of #sign.
An instance of the Filter class is created by passing a block which is received as a proc and saved into the instance variable #filter, which has a read accessor.
An instance of the NumberSet class is created by passing the array, which is saved into the instance variable #arr.
NumberSet#process is passed three arguments: the Enumerable method :reject or :select (saved into op), the SignFilter instance (sf) and the Filter instance (f).
Within NumberSet#process, #arr is sent op, which creates an enumerator (arr.reject or arr.select).
The SignFilter lambda is called on each element of the enumerator. An array comprised of a subcollection of #arr is returned.
The returned array is sent op, creating another reject or select enumerator.
The Filter proc is called on the each element of the new enumerator, causing the desired array to be returned.
Considering that both reject and select are not necessary (either would do), it would have been simpler to just replace .send(op) in NumberSet#process with, say, reject, but I chose to do it this way just to illustrate the generalization.
Notice that it would be easy to generalize NumberSet#process to process(sf,f,o), where, as now, sf and f provide filters and o would be an instance of an Operation class that specifies a proc to send to the filtered subcollection of #arr to invoke an Enumerable method with a block (map, group_by and so on).
Since this appears to be a homework question, I'm not going to give you the full implementation, but I'll see you on your way. The big thing you need to realize here is that methods such as [] and | can be defined as normal methods in Ruby. In Ruby, you simply send messages (such as []) to a "receiver". How you handle those methods are defined via def instructions on your class definition. So, for example:
class Filter
def |(other_filter)
# Do some work to build a new filter which is a union of this filter and other_filter
end
end
class SignFilter < Filter
# SignFilter inherits the & method from Filter, and you can then go on to implement SignFilter-specific functionality
# ...
end
class NumberSet
def [](filter)
# Given a filter, apply each of the numbers of this NumberSet to the filter, and return those which pass the filter
end
end
To invoke those methods, would do something like:
filter = Filter.new {|num| num.even? }
sign_filter = SignFilter.new(:non_negative)
union_filter = filter | sign_filter
This third line is equivalent to calling:
union_filter = filter.|(sign_filter)
or:
union_filter = filter.send("|", sign_filter)
In all three cases, the "|" message is sent to the the filter instance, with sign_filter as an additional argument. You could also do something like:
numset = NumberSet.new(1,2,3,4,5)
filtered_numbers = numset[union_filter]
This second line is equivalent to:
numset.[](union_filter)
# or
numset.send("[]", union_filter)
The original syntax is just syntactic sugar for those method calls - it's just there because it makes Ruby code look nicer, and helps the programmer mentally map it to common conventions for those kinds of operations.
I'm a self taught programmer and started off with Ruby. I'm currently trying to learn algorithms and data structures and noticed something called a linked list. It looks like Ruby doesn't have that data structure (maybe in Array?). I'm familiar with arrays and hashes.
How would you describe/explain what a linked list is for someone coming from my background?
Linked lists are rather simple: they are lists which are created by linking the elements together. (Kind of obvious, when you think about it, no?)
In its most basic form, a linked list is simply either empty or a pair. The first element of the pair is a value, and the second element of the pair is a linked list representing the rest of the values.
Traditionally, the pair is called a cons cell, the first element is called the head or the car of the list and the second element is called the tail or the cdr of the list. The empty list is called Nil or simply [].
Here is an extremely simple implementation of a linked list in Ruby, which uses nothing but functions to implement a linked list (and booleans and conditionals, while we're at it):
True = ->(iff, _) { iff }
False = ->(_, els) { els }
Pair = ->(first, rest) { -> x { x.(first, rest) }}
First = -> list { list.(True ) }
Rest = -> list { list.(False) }
Here, we have a simple list with three elements:
List = Pair.(1, Pair.(2, Pair.(3, nil)))
First.(Rest.(List))
# => 2
A more realistic object-oriented encoding of a list looks like this:
class List
def cons(el) Pair.new(el, self) end
Empty = new
class Pair < self
attr_reader :first, :rest
def initialize(first, rest=Empty)
self.first, self.rest = first, rest
end
private
attr_writer :first, :rest
end
end
Again, a list with two elements:
list1 = List::Pair.new(1, List::Pair.new(2, List::Pair.new(3, List::Empty)))
# corresponds to the list [1, 2, 3]
list1.rest.first
# => 2
list2 = List::Empty.cons(6).cons(5).cons(4)
# List[4, 5, 6]
list2.rest.first
# => 5
A more complete and Rubyish implementation might look like this:
class List
include Enumerable
def self.[](*els) els.reverse_each.inject(Empty, &:cons) end
def cons(el) Pair[el, self] end
def prepend(prefix)
case
when empty? then prefix
when prefix.empty? then self
else prepend(prefix.rest).cons(prefix.first)
end
end
def to_s; "List[#{map(&:to_s).join(', ')}]" end
def inspect; "List[#{map(&:inspect).join(', ')}]" end
def each; return enum_for(__method__) unless block_given? end
class << Empty = new
def empty?; true end
alias_method :inspect, def to_s; 'Empty' end
freeze
end
Empty.freeze
class Pair < self
def initialize(first, rest=Empty)
self.first, self.rest = first, rest
freeze
end
def empty?; false end
def each(&blk)
return super unless block_given?
yield first
rest.each(&blk)
end
private
attr_writer :first, :rest
protected
attr_reader :first, :rest
class << self; alias_method :[], :new end
freeze
end
freeze
end
Some examples:
list1 = List::Pair[1, List::Pair[2, List::Pair[3, List::Empty]]]
# => List[1, 2, 3]
list2 = List::Empty.cons(6).cons(5).cons(4)
# => List[4, 5, 6]
list3 = List[7, 8, 9]
# => List[7, 8, 9]
list4 = list3.prepend(list2).prepend(list1)
# => List[1, 2, 3, 4, 5, 6, 7, 8, 9]
list4.partition(&:odd?)
# => [[1, 3, 5, 7, 9], [2, 4, 6, 8]]
In computer science, a linked list is a data structure consisting of a group of nodes which together represent a sequence. Under the simplest form, each node is composed of a data and a reference (in other words, a link) to the next node in the sequence; more complex variants add additional links. This structure allows for efficient insertion or removal of elements from any position in the sequence.
http://en.wikipedia.org/wiki/Linked_list
Here is a implementation on ruby: http://matt.weppler.me/2013/08/14/implementing-a-linked-list-in-ruby.html
Kudos for studying Ruby one of my favorites languages.
I'm preparing for a technical interview and will be asked to write the algorithm for a linked list in ruby. I understand linked lists completely, but have struggled writing the code. Can someone show me how this is done? I started it below..
class Node
def initialize(item)
#item = item
#next = nil
end
end
You almost did it, really. I can give you very old-school, Lisp-like implementation, if you are brave enough to show it to your interviewer. In this approach, list is a pair (two elements touple), which first element contains the element, and second contains another pair, etc, etc. The last pair have nil as a second element. And here is the whole implementation of the list in Ruby:
class Pair
attr_reader :car, :cdr
def initialize(car, cdr=nil)
#car = car
#cdr = cdr
end
end
To construct the list, just use a lot of parenthesis, like in old, good Lisp:
list = Pair.new(1, Pair.new(2, Pair.new(3)))
Now, the world is yours. You can do whatever you want with the list, using simple recursion. Here is an example of recursive inspect:
class Pair
def inspect
if cdr.nil?
car.inspect
else
"#{car.inspect}, #{cdr.inspect}"
end
end
end
pry(main)> list = Pair.new(1, Pair.new(2, Pair.new(3)))
=> 1, 2, 3
As you mentioned in a comment, you want to search the list. Here is the code for this:
class Pair
def find(index)
find_ index, 0
end
def find_(index, i)
if index == i
car
else
cdr.find_ index, i+1
end
end
end
pry(main)> list.find 2
=> 3
This is the standard Church Encoding of Lists (and Booleans):
True = ->(iff, _) { iff }
False = ->(_, els) { els }
Pair = ->(first, rest) { -> x { x.(first, rest) }}
First = -> list { list.(True ) }
Rest = -> list { list.(False) }
List = Pair.(1, Pair.(2, nil))
First.(Rest.(List))
# => 2
It's not what you would actually write in Ruby, of course, but it is very simple and demonstrates an understanding of one of the most important principles of programming: code is data and data is code.
Here's a more realistic object-oriented encoding of lists:
class List
include Enumerable
def self.[](*els) els.reverse_each.inject(Empty, &:cons) end
def cons(el) Pair[el, self] end
def prepend(prefix)
case
when empty? then prefix
when prefix.empty? then self
else prepend(prefix.rest).cons(prefix.first)
end
end
def to_s; "List[#{map(&:to_s).join(', ')}]" end
def inspect; "List[#{map(&:inspect).join(', ')}]" end
def each; return enum_for(__method__) unless block_given? end
class << Empty = new
def empty?; true end
alias_method :inspect, def to_s; 'Empty' end
freeze
end
Empty.freeze
class Pair < self
def initialize(first, rest=Empty)
self.first, self.rest = first, rest
freeze
end
def empty?; false end
def each(&blk)
return super unless block_given?
yield first
rest.each(&blk)
end
private
attr_writer :first, :rest
protected
attr_reader :first, :rest
class << self; alias_method :[], :new end
freeze
end
freeze
end
Note that there are absolutely no conditionals and no loops in the code. That is always a good sign for object-oriented code: polymorphic method calls are more powerful than conditionals anyway, oftentimes, there simply is no need for conditionals.
Some examples:
list1 = List::Pair[1, List::Pair[2, List::Pair[3, List::Empty]]]
# => List[1, 2, 3]
list2 = List::Empty.cons(6).cons(5).cons(4)
# => List[4, 5, 6]
list3 = List[7, 8, 9]
# => List[7, 8, 9]
list4 = list3.prepend(list2).prepend(list1)
# => List[1, 2, 3, 4, 5, 6, 7, 8, 9]
list4.partition(&:odd?)
# => [[1, 3, 5, 7, 9], [2, 4, 6, 8]]
Unfortunately, this object-oriented encoding will blow the stack for larger lists (on my system List[*(1..9338)].each {} still works, but 9339 doesn't), even though each is tail-calling itself and thus should run in O(1) stack space. As Guy L. Steele pointed out multiple times, OO languages must support proper tail calls, otherwise you are required to break OO in order to avoid blowing the stack. (prepend is not coded for tail-calls, but it can be rewritten that way.)