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

Discussion in 'Ruby' started by illocutionist, Mar 5, 2004.

  1. # 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
    illocutionist, Mar 5, 2004
    #1
    1. Advertising

  2. illocutionist

    Bill Kelly Guest

    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

    >> x = "a"

    => "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...
    >> x.chop!

    => ""
    >> x

    => ""
    # 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...
    >> x.size - 1

    => -1

    # Hmm, so . . .
    >> x[x.size - 1] = 122

    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
    Bill Kelly, Mar 5, 2004
    #2
    1. Advertising

  3. illocutionist

    Mark Hubbart Guest

    Hi,

    On Mar 5, 2004, at 1:09 AM, illocutionist wrote:

    > # 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...
    >> 'cba'.pred!

    => "cz"
    >> 'cba'.pred!.succ!

    => "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
    Mark Hubbart, Mar 5, 2004
    #3
  4. On Fri, Mar 05, 2004 at 06:09:43PM +0900, illocutionist wrote:
    > # 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
    Mauricio Fernández, Mar 6, 2004
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. nadz
    Replies:
    1
    Views:
    303
    jeffc
    Dec 9, 2003
  2. Sunfire
    Replies:
    1
    Views:
    472
    Roland Dick
    Nov 10, 2007
  3. Neha
    Replies:
    37
    Views:
    1,374
  4. Hal Fulton

    Time#succ ?

    Hal Fulton, Nov 23, 2003, in forum: Ruby
    Replies:
    7
    Views:
    121
    Niklas Frykholm
    Nov 28, 2003
  5. paul
    Replies:
    10
    Views:
    195
    Tom Werner
    Nov 10, 2006
Loading...

Share This Page