Below is some code I wrote to solve a problem for a course I'm taking. The solution that I have works just fine, however the question called for using a class implementation, meaning we are to adopt whatever solution we come up with into a class. In the first block below is the method that I wrote, and in the second block is the class implementation of the method, they both do pretty much the same thing. However, I am failing to see the benefit of the class adaptation. Also I don't particularly know how much is too much or too little for a single class method to do on it's own. Do I compartmentalize everything? Or do I keep operations that pertain to a certain thing packaged in a single method?
def cipher(coded_message)
input = coded_message.downcase.split("")
cipher = {}
alphabet_array = %w(a b c d e f g h i j k l m n o p q r s t u v w x y z)
alphabet_array.each_with_index {|e,i| cipher[e] = alphabet_array[i-4]}
(0..9).to_a.each{|e| cipher[e.to_s] = e}
%w[# # $ % ^ & *].each{|e| cipher[e] = " "}
%w[. , ! ? ; : -].each{|e| cipher[e] = e}
input.map! {|e| e = cipher[e]}
input = input.join("")
if input.match(/\d+/)
input.gsub!(/\d+/) { |num| num.to_i / 100 }
end
return input
end
class Cipher
def initialize(shift=4,exaggerate=100)
#shift = shift
#exaggerate = exaggerate
end
def create_cipher
#cipher = {}
#alphabet_array = ('a'..'z').to_a
#alphabet_array.each_with_index {|e,i| #cipher[e] = #alphabet_array[i - #shift]}
(0..9).to_a.each{|e| #cipher[e.to_s] = e}
%w[# # $ % ^ & *].each{|e| #cipher[e] = " "}
%w[. , ! ? ; : -].each{|e| #cipher[e] = e}
end
def decode(input=nil)
#input = input
create_cipher
#input = #input.downcase.split("")
#input.map! {|e| e = #cipher[e]}
#input = #input.join("")
if #input.match(/\d+/)
#input.gsub!(/\d+/) { |num| num.to_i / #exaggerate }
end
return #input
end
end
I would argue that the biggest benefit of moving that code from a method into a class is testability and maintainablity. It is easier to test in isolation and that new class will probably be stable for a long period of time.
Related
I want to implement a merge sort for a single linked list in Ruby.
This code is running without any error but doesn't output as expected.
class Node
attr_accessor :data, :next
def initialize(value)
#data = value
#next = nil
end
end
Merge sort method:
def mergesort(head)
return head if !head || !head.next
a, b = frontbacksplit(head)
mergesort(a)
mergesort(b)
c = sortedmerge(a, b) #something is going wrong here
end
This method is used to divide the list into two sublists:
def frontbacksplit(head)
slow = head
fast = head.next
until fast.nil?
fast = fast.next
unless fast.nil?
slow = slow.next
fast = fast.next
end
end
a = head
b = slow.next
slow.next = nil
[a, b]
end
There may be a mistake in this method:
def sortedmerge(a, b)
result = nil
if a.nil?
return b
elsif b.nil?
return a
end
if a.data <= b.data
result = a
result.next = sortedmerge(a.next, b)
else
result = b
result.next = sortedmerge(a, b.next)
end
result
end
The problem is in the mergesort method. The original implemantation is defined as:
void MergeSort(Node** headRef)
{
...
MergeSort(&a);
MergeSort(&b);
*headRef = SortedMerge(a, b);
}
This means it is changing the the contents of a and b.
Since Ruby does not have such call by reference semantics, you simply forgot to assign the result back into a and b in the Ruby version to duplicate this behavior.
The fix:
def mergesort(head)
...
a = mergesort(a)
b = mergesort(b)
sortedmerge(a, b)
end
I am trying to create a multithreaded version of a sorting algorithm. I do not understand why this algorithm always returns just Array[1] instead of the full array.
class Array
def quick_sort
return self if self.length <= 1
pivot = self[0]
if block_given?
less, greater_equals = self[1..-1].partition { yield(x, pivot) }
else
less, greater_equals = self[1..-1].partition { |x| x < pivot }
end
l = []
g = []
Process.fork {l = less.quick_sort }
Process.fork {g = greater_equals.quick_sort}
Process.waitall
return l + [pivot] + g
end
end
The local variables l and g are not passed beyond Process.fork. They are only valid within that block. For example,
Process.fork{a = 2}
Process.wait
a #=> NameError: undefined local variable or method `a' for main:Object
In your code, the l and g assignments done before Process.fork are still valid when you call return l + [pivot] + g.
By the way, if you had intended l and g to be passed from Process.fork, then your initialization of these variables prior to Process.fork is meaningless.
From you examples it looks like you are trying to use Process where you actually want to use a thread.
Process: no shared resources with itś caller (Parent)
Thread: shares memory with its Parent
Your example would work if you replaced the Process.fork with Threads:
l = []
g = []
left_thread = Thread.new {l = less.quick_sort }
right_thread = Thread.new {g = greater_equals.quick_sort}
left_thread.join
right_thread.join
return l. + [pivot] + g
I am attempting to memoize my implementation of a Pascal's triangle generator, as a Ruby learning experiment. I have the following working code:
module PascalMemo
#cache = {}
def PascalMemo::get(r,c)
if #cache[[r,c]].nil? then
if c == 0 || c == r then
#cache[[r,c]] = 1
else
#cache[[r,c]] = PascalMemo::get(r - 1, c) + PascalMemo::get(r - 1, c - 1)
end
end
#cache[[r,c]]
end
end
def pascal_memo (r,c)
PascalMemo::get(r,c)
end
Can this be made more concise? Specifically, can I create a globally-scoped function with a local closure more simply than this?
def pascal_memo
cache = [[1]]
get = lambda { |r, c|
( cache[r] or cache[r] = [1] + [nil] * (r - 1) + [1] )[c] or
cache[r][c] = get.(r - 1, c) + get.(r - 1, c - 1)
}
end
p = pascal_memo
p.( 10, 7 ) #=> 120
Please note that the above construct does achieve memoization, it is not just a simple recursive method.
Can this be made more concise?
It seems pretty clear, IMO, and moduleing is usually a good instinct.
can I create a globally-scoped function with a local closure more simply than this?
Another option would be a recursive lambda:
memo = {}
pascal_memo = lambda do |r, c|
if memo[[r,c]].nil?
if c == 0 || c == r
memo[[r,c]] = 1
else
memo[[r,c]] = pascal_memo[r - 1, c] + pascal_memo[r - 1, c - 1]
end
end
memo[[r,c]]
end
pascal_memo[10, 2]
# => 45
I have found a way to accomplish what I want that is slightly more satisfactory, since it produces a function rather than a lambda:
class << self
cache = {}
define_method :pascal_memo do |r,c|
cache[[r,c]] or
(if c == 0 or c == r then cache[[r,c]] = 1 else nil end) or
cache[[r,c]] = pascal_memo(r-1,c) + pascal_memo(r-1,c-1)
end
end
This opens up the metaclass/singleton class for the main object, then uses define_method to add a new method that closes over the cache variable, which then falls out of scope for everything except the pascal_memo method.
Ruby code is:
a = []
h = {}
2.times.each do |i|
%w(a b c).each do |x|
h[x] = x + i.to_s
end
a << h
end
the result is:
a = [{"c"=>"c1", "b"=>"b1", "a"=>"a1"}, {"c"=>"c1", "b"=>"b1", "a"=>"a1"}]
but i hope the result is:
a = [{"c"=>"c0", "b"=>"b0", "a"=>"a0"}, {"c"=>"c1", "b"=>"b1", "a"=>"a1"}]
who can help me.thx
After a << h you have to do h = {}. This is because you are assigning a new object to h so that it doesn't override the previous values.
[Complementary answer] Are you familiar with the principles of functional programming?
(0..1).map { |n| Hash[("a".."c").map { |c| [c, "#{c}#{n}"] }] }
#=> {"a"=>"a0", "b"=>"b0", "c"=>"c0"}, {"a"=>"a1", "b"=>"b1", "c"=>"c1"}]
I'm trying to learn Ruby, and am going through some of the Project Euler problems. I solved problem number two as such:
def fib(n)
return n if n < 2
vals = [0, 1]
n.times do
vals.push(vals[-1]+vals[-2])
end
return vals.last
end
i = 1
s = 0
while((v = fib(i)) < 4_000_000)
s+=v if v%2==0
i+=1
end
puts s
While that works, it seems not very ruby-ish—I couldn't come up with any good purely Ruby answer like I could with the first one ( puts (0..999).inject{ |sum, n| n%3==0||n%5==0 ? sum : sum+n }).
For a nice solution, why don't you create a Fibonacci number generator, like Prime or the Triangular example I gave here.
From this, you can use the nice Enumerable methods to handle the problem. You might want to wonder if there is any pattern to the even Fibonacci numbers too.
Edit your question to post your solution...
Note: there are more efficient ways than enumerating them, but they require more math, won't be as clear as this and would only shine if the 4 million was much higher.
As demas' has posted a solution, here's a cleaned up version:
class Fibo
class << self
include Enumerable
def each
return to_enum unless block_given?
a = 0; b = 1
loop do
a, b = b, a + b
yield a
end
end
end
end
puts Fibo.take_while { |i| i < 4000000 }.
select(&:even?).
inject(:+)
My version based on Marc-André Lafortune's answer:
class Some
#a = 1
#b = 2
class << self
include Enumerable
def each
1.upto(Float::INFINITY) do |i|
#a, #b = #b, #a + #b
yield #b
end
end
end
end
puts Some.take_while { |i| i < 4000000 }.select { |n| n%2 ==0 }
.inject(0) { |sum, item| sum + item } + 2
def fib
first, second, sum = 1,2,0
while second < 4000000
sum += second if second.even?
first, second = second, first + second
end
puts sum
end
You don't need return vals.last. You can just do vals.last, because Ruby will return the last expression (I think that's the correct term) by default.
fibs = [0,1]
begin
fibs.push(fibs[-1]+fibs[-2])
end while not fibs[-1]+fibs[-2]>4000000
puts fibs.inject{ |sum, n| n%2==0 ? sum+n : sum }
Here's what I got. I really don't see a need to wrap this in a class. You could in a larger program surely, but in a single small script I find that to just create additional instructions for the interpreter. You could select even, instead of rejecting odd but its pretty much the same thing.
fib = Enumerator.new do |y|
a = b = 1
loop do
y << a
a, b = b, a + b
end
end
puts fib.take_while{|i| i < 4000000}
.reject{|x| x.odd?}
.inject(:+)
That's my approach. I know it can be less lines of code, but maybe you can take something from it.
class Fib
def first
#p0 = 0
#p1 = 1
1
end
def next
r =
if #p1 == 1
2
else
#p0 + #p1
end
#p0 = #p1
#p1 = r
r
end
end
c = Fib.new
f = c.first
r = 0
while (f=c.next) < 4_000_000
r += f if f%2==0
end
puts r
I am new to Ruby, but here is the answer I came up with.
x=1
y=2
array = [1,2]
dar = []
begin
z = x + y
if z % 2 == 0
a = z
dar << a
end
x = y
y = z
array << z
end while z < 4000000
dar.inject {:+}
puts "#{dar.sum}"
def fib_nums(num)
array = [1, 2]
sum = 0
until array[-2] > num
array.push(array[-1] + array[-2])
end
array.each{|x| sum += x if x.even?}
sum
end