The opposite of .succ! (though it still may)

I

illocutionist

# An opposite to .succ! Or, a predecessor method for String.

# This little thing is for my own use, and entertainment.
# There are those that might recoil from by beginners drivel, but I
# need a little help...

# I keep getting 'out of range' error no matter what I try
# when "a".pred!

class String

def pred!
begin
# get the ascii value of the last element in string and decrement it...
self[self.size - 1] = (self[self.size - 1] - 1)

if self[self.size - 1] == 96 # 'a' is the last char we want
self.chop! # when 'a'.pred! .chop char
self[self.size - 1] = 122 # set new last element to 'z'
end
return self
end while self.size > 0 # hmmmm...
end
end
 
B

Bill Kelly

Hi,
# An opposite to .succ! Or, a predecessor method for String.

# This little thing is for my own use, and entertainment.
# There are those that might recoil from by beginners drivel, but I
# need a little help...

# I keep getting 'out of range' error no matter what I try
# when "a".pred!

class String

def pred!
begin
# get the ascii value of the last element in string and decrement it...
self[self.size - 1] = (self[self.size - 1] - 1)

if self[self.size - 1] == 96 # 'a' is the last char we want
self.chop! # when 'a'.pred! .chop char
self[self.size - 1] = 122 # set new last element to 'z'
end
return self
end while self.size > 0 # hmmmm...
end
end

IRB can be a big help in trying out bits of code interactively...

irb --simple-prompt
=> "a"

# let's try the first line there...
# self[self.size - 1] = (self[self.size - 1] - 1)
x[x.size - 1] = x[x.size - 1] - 1 => 96
x
=> "`"
# so far so good...

# ...Incidentally, that line can be written shorter,
# using a negative index to index relative to the end
# of the container, and -= method to decrement...
x = "a" => "a"
x[-1] -= 1 # same as: x[x.size - 1] = x[x.size - 1] - 1 => 96
x
=> "`"
# same result...

# OK.. let's try the next line,
# if self[self.size - 1] == 96
x[-1] == 96 # same thing, using simpler index
=> true

# OK continuing on...=> ""
# well we've chopped our lone character down to nothing...

# we're now about to try this line:
# self[self.size - 1] = 122

# Let's see what self.size - 1 would be...=> -1

# Hmm, so . . .
IndexError: index -1 out of string
from (irb):13:in `[]='
from (irb):13



So I guess the routine needs some logic to bail out on
a lone 'a' ... Or bail out when the chop! reduces the
string to zero length? (Not sure what the desired
outcome is .. :)


Hope this helps,

Regards,

Bill
 
M

Mark Hubbart

Hi,

# An opposite to .succ! Or, a predecessor method for String.

# This little thing is for my own use, and entertainment
# There are those that might recoil from by beginners drivel, but I
# need a little help...

# I keep getting 'out of range' error no matter what I try
# when "a".pred!

class String

def pred!
begin
# get the ascii value of the last element in string and decrement it...
self[self.size - 1] = (self[self.size - 1] - 1)

if self[self.size - 1] == 96 # 'a' is the last char we
want
self.chop! # when 'a'.pred! .chop
char
self[self.size - 1] = 122 # set new last element
to 'z'
end
return self
end while self.size > 0 # hmmmm...
end
end

First of all: You're doing too much work! :D there are a couple things
you an do that will make the code smaller, and even easier to read.

Take this line:
self[self.size - 1] = (self[self.size - 1] - 1)

first: when using array notation, there is an easier way to get the
last element. You can leave off the "self.size" and just have the -1
part
self[-1] = (self[-1] - 1)

next, since array notation can be used for both assignment and
retrieval, you can use "-=" :)
self[-1] -= 1 # this decrements the last character

However, I think that there is a logic error in your code...=> "da"

shouldn't "'cba'.pred!.succ!" return 'cba'?

looking at your code, I see that you are decrementing the last
character, then chopping it if it is under-valued. What you really want
to do is decrement the character to it's left, and set the last
character to 'z'.

if self[-1] > 97 # it's bigger than a
self[-1] -= 1
else # it is a. look to the left.
# decrement char to left, set self[-1] to z
# unless there is no char to the left, in which case, return ''
end

There's more, but I'll leave the rest as an exercise ;)

--Mark
 
M

Mauricio Fernández

# An opposite to .succ! Or, a predecessor method for String.

# This little thing is for my own use, and entertainment.
# There are those that might recoil from by beginners drivel, but I
# need a little help...

# I keep getting 'out of range' error no matter what I try
# when "a".pred!

class String

def pred!
begin
# get the ascii value of the last element in string and decrement it...
self[self.size - 1] = (self[self.size - 1] - 1)

if self[self.size - 1] == 96 # 'a' is the last char we want
self.chop! # when 'a'.pred! .chop char
self[self.size - 1] = 122 # set new last element to 'z'
end
return self
end while self.size > 0 # hmmmm...
end
end
"abcd".my_pred_alpha => "abcc"
"abcd".my_succ_alpha => "abce"
"z".my_succ_alpha => "00"
"00".my_pred_alpha
=> "z"

batsman@tux-chan:/tmp$ ruby /tmp/yy.rb
Loaded suite /tmp/yy
Started
.....
Finished in 1.525721 seconds.

5 tests, 20011 assertions, 0 failures, 0 errors


class String
ALPHA = [('0'..'9'), ('A'..'Z'), ('a'..'z')].
inject([]){|a,b| a + b.to_a}.map{|x| x[0]}

def my_succ_alpha
vals = self.unpack("C*")
carry = (vals.size-1).downto(0) do |idx|
if (i = ALPHA.index(vals[idx])) < ALPHA.size - 1
vals[idx] = ALPHA[i+1]
break false
else
vals[idx] = ALPHA[0]
end
end
vals.unshift(ALPHA[0]) if carry
vals.pack("C*")
end

def my_pred_alpha # breaks for "0"
vals = self.unpack("C*")
carry = (vals.size-1).downto(0) do |idx|
if (i = ALPHA.index(vals[idx])) > 0
vals[idx] = ALPHA[i-1]
break false
else
vals[idx] = ALPHA[-1]
end
end
vals.shift if carry
vals.pack("C*")
end

def my_succ # just operating on byte values
vals = self.unpack("C*")
carry = (vals.size-1).downto(0) do |idx|
if vals[idx] < 255
vals[idx] += 1
break false
else
vals[idx] = 0
end
end
vals.unshift(0) if carry
vals.pack("C*")
end

def my_pred # 'reverse' of my_succ
vals = self.unpack("C*")
carry = (vals.size-1).downto(0) do |idx|
if vals[idx] > 0
vals[idx] -= 1
break false
else
vals[idx] = 255
end
end
vals.shift if carry
vals.pack("C*")
end
end

require 'test/unit'

class TC_my_succ < Test::Unit::TestCase
def arr_succ(a)
a.pack("C*").my_succ.unpack("C*")
end

def arr_pred(a)
a.pack("C*").my_pred.unpack("C*")
end

def test_rand
5000.times do
txt = (0..rand(20)).map{rand(255)}.pack("C*")
assert_equal(txt, txt.my_succ.my_pred)
assert_equal(txt, txt.my_pred.my_succ)
end
end

def test_rand_alpha
5000.times do
txt = (0..rand(20)).inject("") do |a,b|
a << String::ALPHA[rand(String::ALPHA.size)]
end
next if txt == "0" # my_pred_alpha is undefined
assert_equal(txt, txt.my_succ_alpha.my_pred_alpha)
assert_equal(txt, txt.my_pred_alpha.my_succ_alpha)
end
end

def test_my_pred_alpha
assert_equal("aa", "ab".my_pred_alpha)
assert_equal("aZ", "aa".my_pred_alpha)
assert_equal("z", "00".my_pred_alpha)
assert_equal("0", "1".my_pred_alpha)
assert_equal("00", "01".my_pred_alpha)
assert_equal("9", "A".my_pred_alpha)
end

def test_my_succ
assert_equal("ab", "aa".my_succ)
assert_equal("a:", "a9".my_succ)
assert_equal([0, 0], arr_succ([255]))
assert_equal([?b, 0], arr_succ([?a, 255]))
end

def test_my_pred
assert_equal("aa", "ab".my_pred)
assert_equal("a9", "a:".my_pred)
assert_equal([0, 255], arr_pred([1,0]))
assert_equal([255], arr_pred([0,0]))
assert_equal([?a, 255], arr_pred([?b, 0]))
end
end


--
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

*** PUBLIC flooding detected from erikyyy
<lewnie> THAT's an erik, pholx.... ;)
-- Seen on #LinuxGER
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top