Ruby Class Instance Variable not cleared between method call : Integer class - ruby

I have the following code for an assignment. After much debugging I found what was happening
class Integer
def initialize()
#ans = ""
end
def ans
#ans = ""
end
def ans=(value)
#ans = value
end
def to_base(base)
# convert given number into the base
# figure out how to make it the most efficient
num = self
r = 0
loop do
r = num % base # modulus
#ans = r.to_s + #ans.to_s # add to answer
num /= base # division
break unless num != 0
end
english = #ans # return value
end
def to_oct
self.to_base(8)
end
end
puts 8.to_oct
puts 8.to_base(2)
Output:
10
100010
The output for the binary version should be 1000 not 100010
What it did was append the first instance of the class 8.to_oct onto the second call 8.to_base(2)
Is there a way to have this cleared as I want to use the same number (8) in this example and convert it to various base numbers. what am I doing wrong in my class?
Thanks!

Related

Exponentiation not working

I'm new to programming, especially in Ruby so I've been making some basic projects. I have this code and as far as I know, it should work, but it gives results that I don't expect
The program takes a and B and returns a^b. I did this as a programming exercise, hence why I didn't just go a**b.
class Exponate
attr_accessor :args
def initialize args = {}
#args = args
#ans = nil
end
def index
#args[:b].times {
#ans = #args[:a] * #args[:a]
}
puts #ans
end
end
e = Exponate.new(:a => 32, :b => 6)
e.index
e.args[:a] = 5
e.index
Returns
1024 # Should be 1_073_741_824
25 # Should be 15_625
But they are definitely not that
You can write like this:
class Exponate
attr_accessor :args, :ans
def initialize args = {}
#args = args
end
def index
#ans = 1 # multiplication will start from 1
#args[:b].times {
#ans *= #args[:a] #same as #ans = #ans * #args[:a]
}
puts #ans
end
end
#ans = #args[:a] * #args[:a] will return the same value, no matter how many times called, you need to reference the accumulator variable in some way to make use of the cycle.
Using an instance variable for a local does not seem right - their lifetime is longer, so after method exits they cannot not be collected if the whole object is still referenced somewhere. Also the #s are more error-prone - if you make a typo (for example - #asn instead of #ans), you'll get nil instead of NameError, it may be harder to debug, so better to write this way:
def index
ans = 1
args[:b].times {
ans *= args[:a]
}
puts ans
end
For loops with an accumulator in ruby it's better to use Enumerable#inject:
#ans = #args[:b].times.inject(1){|acc,v| acc * #args[:a]}
this way it's less likely to forget initialisation.

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

Composing slices of slices

I've been thinking about this problem for a couple of days now and I can't find an elegant solution for the life of me.
In my app I have a Text class which is just a wrapper around String:
class Text < Struct.new(:string, :style)
def [](start, len)
Text.new(string[start, len], style)
end
def length
string.length
end
def to_s
case style
when :bold then "**" + string + "**"
when :italic then "_" + string +"_"
else string
end
end
def inspect
"<[#{style}] #{string}>"
end
end
I also have a Line class that basically is an array of Text objects:
class Line < Struct.new(:texts)
def [](start, len)
# TODO Should return a new Line object.
end
def length
texts.map(&:length).reduce(&:+)
end
def to_s
texts.map(&:to_s).join
end
def inspect
texts.map(&:inspect).join(" ")
end
end
The question is, how can I implement #[] in Line so that it returns a new Line object which "correctly" slices the contained Text objects?
The idea is to imitate the slicing behavior of String. For example:
line = Line.new([Text.new("abcdef", :bold), Text.new("ghijkl", :default)])
puts line[0, 2] # => **ab**
p line[0, 2] # => "<[:bold] ab>"
puts line[3, 6] # => **def**ghi
p line[3, 6] # => "<[:bold] def> <[:default] ghi>"
Keep in mind that the length of a Text object is the length of its string member:
a = Text.new("abc", :bold)
puts a # => **abc**
puts a.length # => 3
And the length of a Lineobject is just the sum of the lengths of its texts:
line = Line.new([Text.new("abcdef", :bold), Text.new("ghijkl", :default)])
puts line.length # => 12
Everything I've tried involves an stupid amount of complicated conditionals and convoluted temporary variables, and I feel there's a simpler solution lurking underneath it all.
Here's a snippet that may help you:
class Line
def pos_to_index_and_offset(pos)
raise ArgumentError if !texts or texts.empty?
index = 0
offset = pos
while offset >= (size = texts[index].length)
offset -= size
index += 1
raise ArgumentError if index > texts.length
end
return [index, offset]
end
end

How to print numbers in hex with leading zero

Is there a better method to display a number in hex with leading 0? I tried:
i.to_s(16)
but
2.to_s(16) #=> "2"
where I expect "02". I tried the print format:
"%02x" % i
which works for 2, but
"%02x" % 256 #=> "100"
where I want "0100". So I came up with this:
class Integer
def to_hex_string
("%0x" % self).size % 2 == 0 ? "%0x" % self : "%0#{("%0x" % self).size+1}x" % self
end
end
It works:
2.to_hex_string #=> "02"
256.to_hex_string #=> "0100"
It works also with class Bignumber, but it looks strange that such an easy request needs a trick like this. Any better idea?
for 2-digit hex values this works:
def to_hex(int)
int < 16 ? '0' + int.to_s(16) : int.to_s(16)
end
Yes, it bugs:
Let's try this:
class Integer
def to_hex_string
"0#{to_s(16)}"
end
end
class BigNumber
def to_hex_string
"0#{to_s(16)}"
end
end
class String
def to_hex_string
self.unpack('H*').first
end
def to_bytes_string
unless self.size % 2 == 0
raise "Can't translate a string unless it has an even number of digits"
end
raise "Can't translate non-hex characters" if self =~ /[^0-9A-Fa-f]/
[self].pack('H*')
end
def to_bignum
self.bytes.inject { |a,b| (a << 8) + b }
end
end
p a="ff"*192 # => "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
p bytestring=a.to_bytes_string # => "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
p bytestring.to_hex_string # => "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
p biga=a.to_bytes_string.to_bignum # => 2410312426921032588580116606028314112912093247945688951359675039065257391591803200669085024107346049663448766280888004787862416978794958324969612987890774651455213339381625224770782077917681499676845543137387820057597345857904599109461387122099507964997815641342300677629473355281617428411794163967785870370368969109221591943054232011562758450080579587850900993714892283476646631181515063804873375182260506246992837898705971012525843324401232986857004760339316735
And the BUG is here:
p biga.to_hex_string # => "0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
Where does this 0 come from????
What is even more strange is my complicated solution is working:
p ("%0x" % biga).size % 2 == 0 ? "%0x" % biga : "%0#{("%0x" % biga).size+1}x" % biga # => "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
Maybe a bug in "0#{to_s(16)}"?
Use "%.2x", where 2 is the amount of digits you want.
"%.2x" % 0 # => "00"
"%.2x" % 15 # => "0f"
"%.2x" % 255 # => "ff"
This was the first hit on Google when I was just trying to solve this. I had to find a couple of other posts to finish up my solution but I think this is clean.
class Fixnum
def to_hex(bits)
rjust = (bits/4 + (bits.modulo(4)==0 ? 0 : 1))
"0x" + self.to_s(16).rjust(rjust, "0")
end
end
You are making this way too complicated. If you want to print an integer in hexadecimal with a leading zero, then it is just
class Integer
def to_hex_string
"0#{to_s(16)}"
end
end
2.to_hex_string # => 02
256.to_hex_string # => 0100

Reverse words of a string in Ruby?

I am trying to reverse the words of a string in Ruby, without using the reverse method. I want to implement the known algorithm of:
Reverse the whole string
Reverse each word in the reversed string.
Here is what I have come up with:
class String
def custom_reverse(start, limit)
i_start = start
i_end = limit - 1
while (i_start <= i_end)
tmp = self[i_start]
self[i_start] = self[i_end]
self[i_end] = tmp
i_start += 1
i_end -= 1
end
return self
end
def custom_reverse_words
self.custom_reverse(0, self.size)
i_start = 0
i_end = 0
while (i_end <= self.length)
if (i_end == self.length || self[i_end] == ' ')
self.custom_reverse(i_start, i_end)
i_start += 1
end
i_end += 1
end
end
end
test_str = "hello there how are you"
p test_str.custom_reverse_words
But the results are "yahthello ow ou er ereh"
What am I missing?
The gist of any reverse operation is to iterate over elements in the reverse order of what you'd normally do. That is, where you'd usually use the set (0..N-1) you'd instead go through (N-1..0) or more specifically N-1-i where i is 0..N-1:
class String
def reverse_words
split(/\s+/).map{|w|wl=w.length-1;(0..wl).map{|i|w[wl-i]}.join}.join(' ')
end
end
puts "this is reverse test".reverse_words.inspect
# => "siht si esrever tset"
The same principle can be applied to the words in a given string.
Interview questions of this sort are of highly dubious value. Being "clever" in production code is usually a Very Bad Idea.
Here's one way to reverse an array without using the built-in reverse:
class Array
def reverse
tmp_ary = self.dup
ret_ary = []
self.size.times do
ret_ary << tmp_ary.pop
end
ret_ary
end
end
%w[a b c].reverse # => ["c", "b", "a"]
tmp_ary.pop is the secret. pop removes elements from the end of the array.
The cleanest solution I could think of is:
class Array
def my_reverse
sort_by.with_index {|_, i| -i}
end
end
class String
def words
split(/\W+/)
end
def revert_words
words.my_reverse.join(' ')
end
def revert_each_word
words.map {|w| w.chars.my_reverse.join}.join(' ')
end
end
Once you define a simple and efficient array reverser:
def reverse_array(a)
(a.length / 2).times {|i| a[i],a[-(i+1)] = a[-(i+1)],a[i]}
a
end
You can reverse a sentence pretty straightforwardly:
def reverse_sentence(s)
reverse_array(s.split('')).join.split(" ").map{|w| reverse_array(w.split('')).join}.join(" ")
end
reverse_sentence "Howdy pardner" # => "pardner Howdy"
Here's another way:
class String
def reverse_words
split.inject([]){|str, word| str.unshift word}.join(' ')
end
def reverse_chars
each_char.inject([]){|str, char| str.unshift char}.join('')
end
end
Revised
Carey raises a good point, reverse_chars can be simplified, since string is already an Enumerable:
class String
def reverse_chars
each_char.inject(""){|str, char| str.insert(0, char) }
end
end

Resources