




Ruby Programming Language









MutuallyRecursive Functions
Ruby doesn't seem to do mutuallyrecursive functions. Or is it some particular idiom I know not about? I am using an array to implement them, and it stinks a bit. Any way to do it? Thanks. Revence
Revence Kalibwani wrote: > Ruby doesn't seem to do mutuallyrecursive functions. Or is it some > particular idiom I know not about? I am using an array to implement > them, and it stinks a bit. Any way to do it? > Thanks. > Revence
Could you show us what you mean? I for one do not know what a mutually recursive function is. Dan
Dan Zwell wrote: > Revence Kalibwani wrote: >> Ruby doesn't seem to do mutuallyrecursive functions. Or is it some >> particular idiom I know not about? I am using an array to implement >> them, and it stinks a bit. Any way to do it? > Could you show us what you mean? I for one do not know what a mutually > recursive function is.
I have written it all out. Now, since I'm fresh to this list, I dunno if attachments show. Indulge me, please. I'll paste all the code (it's a bit literate') and also attach it (as mutrec.rb). :) By the way, ruby v is: 1.8.5 #! /usr/bin/ruby # Two examples of a mutuallyrecursive function. # These are functions that depend on each other  recursively. # even and odd: # If a number is zero, then it is even. Otherwise, it is even if the one before it is odd. # A number is odd if it is not zero. Otherwise, it is odd if it the one before it is even. :o) # This is the canonical example. def my_even(x) x == 0 or odd(x  1) end def my_odd(x) x != 0 and even(x  1) end # That is, of course, a silly way to implemet even and odd. So, let me give you the problem # I was trying to solve. # # To generate the lettering similar to that above the spreadsheet columns, where the first # column has 'A', the second 'B' ... the twentysixth 'Z'. Then, the twentyseventh has # 'AA', the twentyeight has 'AB', and so on. This is recursive by nature. Here is what # should work: Letters = ['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'] def alphabetise(pos) pile_letters(0, pos) # LABEL: 1 end def pile_chars(thus_far, pos) len = Letters.length if pos < len then Letters[pos] else alphabeticise(thus_far) + pile_chars(thus_far + 1, pos  len) end end # Labels: # 1. That's where it fails. I guess 'tis because the scope is searched backwards # from that point. # OCaml, for example, requires me to put the `and' keyword between mutuallyrecursive # functions. I'd not mind doing that in Ruby, but I don't know how. n00b. ;) # Also, it works in That Other Language. # # Now, the (dirty) solution I found. I think you will help me with how to get it done # without all this voodoo: Funcs = [lambda do pos Funcs[1].call(0, pos) end, lambda do thus_far, pos len = Letters.length if pos < len then Letters[pos] else Funcs[0].call(thus_far) + Funcs[1].call(thus_far + 1, pos  len) end end] def main(args) puts Funcs[0].call((26 * 26)  1) # Prints A to Z. But see how unRubyistic it is! # puts alphabetise(675) # This fails. # if my_even 4 and my_odd 5 then 0 else 1 end # This also fails 0 end exit(main(ARGV))
[
mutrec.rb ]
#! /usr/bin/ruby # Two examples of a mutuallyrecursive function. # These are functions that depend on each other  recursively. # even and odd: # If a number is zero, then it is even. Otherwise, it is even if the one before it is odd. # A number is odd if it is not zero. Otherwise, it is odd if it the one before it is even. :o) # This is the canonical example. def my_even(x) x == 0 or odd(x  1) end def my_odd(x) x != 0 and even(x  1) end # That is, of course, a silly way to implemet even and odd. So, let me give you the problem # I was trying to solve. # # To generate the lettering similar to that above the spreadsheet columns, where the first # column has 'A', the second 'B' ... the twentysixth 'Z'. Then, the twentyseventh has # 'AA', the twentyeight has 'AB', and so on. This is recursive by nature. Here is what # should work: Letters = ['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'] def alphabetise(pos) pile_letters(0, pos) # LABEL: 1 end def pile_chars(thus_far, pos) len = Letters.length if pos < len then Letters[pos] else alphabeticise(thus_far) + pile_chars(thus_far + 1, pos  len) end end # Labels: # 1. That's where it fails. I guess 'tis because the scope is searched backwards # from that point. # OCaml, for example, requires me to put the `and' keyword between mutuallyrecursive # functions. I'd not mind doing that in Ruby, but I don't know how. n00b. ;) # Also, it works in That Other Language. # # Now, the (dirty) solution I found. I think you will help me with how to get it done # without all this voodoo: Funcs = [lambda do pos Funcs[1].call(0, pos) end, lambda do thus_far, pos len = Letters.length if pos < len then Letters[pos] else Funcs[0].call(thus_far) + Funcs[1].call(thus_far + 1, pos  len) end end] def main(args) puts Funcs[0].call((26 * 26)  1) # Prints A to Z. But see how unRubyistic it is! # puts alphabetise(675) # This fails. # if my_even 4 and my_odd 5 then 0 else 1 end # This also fails 0 end exit(main(ARGV))
For the even and odd example, it works if you remplace odd by my_odd in the my_even function, and even by my_even in the my_odd function. Like this: def my_even(x) x == 0 or my_odd(x  1) end def my_odd(x) x != 0 and my_even(x  1) end my_even(10) #=> true Hope this helps.  Bruno Michel
Bruno Michel wrote: > For the even and odd example, it works if you remplace odd by my_odd > in the my_even function, and even by my_even in the my_odd function. > Like this: > def my_even(x) > x == 0 or my_odd(x  1) > end > def my_odd(x) > x != 0 and my_even(x  1) > end > my_even(10) #=> true > Hope this helps.
Yeah. Solved it. Lots of typos. That happens under stress. Thanks a lot, everyone. :)
On 6/7/07, Revence Kalibwani <revenc@gmail.com> wrote:
> Bruno Michel wrote: > > For the even and odd example, it works if you remplace odd by my_odd > > in the my_even function, and even by my_even in the my_odd function. > > Like this: > > def my_even(x) > > x == 0 or my_odd(x  1) > > end > > def my_odd(x) > > x != 0 and my_even(x  1) > > end > > my_even(10) #=> true > > Hope this helps. > Yeah. Solved it. Lots of typos. That happens under stress. Thanks a lot, > everyone. :)
For this very case, String#succ and String.succ! might be helpful ('A'.succ > 'B', 'Z'.succ > 'AA').
On 6/7/07, Revence Kalibwani <revenc@gmail.com> wrote: > # That is, of course, a silly way to implemet even and odd. So, let me give you the problem > # I was trying to solve. > # > # To generate the lettering similar to that above the spreadsheet columns, where the first > # column has 'A', the second 'B' ... the twentysixth 'Z'. Then, the twentyseventh has > # 'AA', the twentyeight has 'AB', and so on. This is recursive by nature. Here is what > # should work:
I may be missing something, but.. If you just want to do that then try something like this. arr = [] ("a".."ff").each {x arr << x} p arr Harry  A Look into Japanese Ruby List in English http://www.kakueki.com/
Hi 
On Thu, 7 Jun 2007, Harry Kakueki wrote: > On 6/7/07, Revence Kalibwani <revenc @gmail.com> wrote: >> # That is, of course, a silly way to implemet even and odd. So, let >> me give you the problem >> # I was trying to solve. >> # >> # To generate the lettering similar to that above the spreadsheet >> columns, where the first >> # column has 'A', the second 'B' ... the twentysixth 'Z'. Then, the >> twentyseventh has >> # 'AA', the twentyeight has 'AB', and so on. This is recursive by >> nature. Here is what >> # should work: > I may be missing something, but.. > If you just want to do that then try something like this. > arr = [] > ("a".."ff").each {x arr << x} > p arr
Worksaving tip for the day: p [*"a".."ff"] :) David  Q. What is THE Ruby book for Rails developers? A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black) (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf) Q. Where can I get Ruby/Rails onsite training, consulting, coaching? A. Ruby Power and Light, LLC (http://www.rubypal.com)
On 6/7/07, dbl@wobblini.net <dbl@wobblini.net> wrote:
> Hi  > On Thu, 7 Jun 2007, Harry Kakueki wrote: > > I may be missing something, but.. > > If you just want to do that then try something like this. > > arr = [] > > ("a".."ff").each {x arr << x} > > p arr > Worksaving tip for the day: > p [*"a".."ff"] > :) > David >  > Q. What is THE Ruby book for Rails developers? > A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black) > (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf) > Q. Where can I get Ruby/Rails onsite training, consulting, coaching? > A. Ruby Power and Light, LLC (http://www.rubypal.com)
I was going to do this. p ("a".."ff").each {x p x} But I didn't want it to run off the screen. But you did the same thing in a better way. Thanks for the tip. Harry  A Look into Japanese Ruby List in English http://www.kakueki.com/
On 6/7/07, Harry Kakueki <list.p@gmail.com> wrote:
> On 6/7/07, dbl @wobblini.net <dbl @wobblini.net> wrote: > > Worksaving tip for the day: > > p [*"a".."ff"] > > :) > > David > >  > > Q. What is THE Ruby book for Rails developers? > > A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black) > > (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf) > > Q. Where can I get Ruby/Rails onsite training, consulting, coaching? > > A. Ruby Power and Light, LLC (http://www.rubypal.com) > I was going to do this. > p ("a".."ff").each {x p x} > Harry
Oops. Don't need 2 p's. ("a".."ff").each {x p x} Harry  A Look into Japanese Ruby List in English http://www.kakueki.com/
On Jun 7, 2007, at 5:06 AM, dbl@wobblini.net wrote:
> Hi  > On Thu, 7 Jun 2007, Harry Kakueki wrote: >> On 6/7/07, Revence Kalibwani <revenc@gmail.com> wrote: >>> # That is, of course, a silly way to implemet even and odd. >>> So, let me give you the problem >>> # I was trying to solve. >>> # >>> # To generate the lettering similar to that above the >>> spreadsheet columns, where the first >>> # column has 'A', the second 'B' ... the twentysixth 'Z'. >>> Then, the twentyseventh has >>> # 'AA', the twentyeight has 'AB', and so on. This is >>> recursive by nature. Here is what >>> # should work: >> I may be missing something, but.. >> If you just want to do that then try something like this. >> arr = [] >> ("a".."ff").each {x arr << x} >> p arr > Worksaving tip for the day: > p [*"a".."ff"] > :)
seems a bit perlish no? cfp:~ > cat a.rb p ('a' .. 'ff').to_a cfp:~ > ruby a.rb ["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", "aa", "ab", "ac", "ad", "ae", "af", "ag", "ah", "ai", "aj", "ak", "al", "am", "an", "ao", "ap", "aq", "ar", "as", "at", "au", "av", "aw", "ax", "ay", "az", "ba", "bb", "bc", "bd", "be", "bf", "bg", "bh", "bi", "bj", "bk", "bl", "bm", "bn", "bo", "bp", "bq", "br", "bs", "bt", "bu", "bv", "bw", "bx", "by", "bz", "ca", "cb", "cc", "cd", "ce", "cf", "cg", "ch", "ci", "cj", "ck", "cl", "cm", "cn", "co", "cp", "cq", "cr", "cs", "ct", "cu", "cv", "cw", "cx", "cy", "cz", "da", "db", "dc", "dd", "de", "df", "dg", "dh", "di", "dj", "dk", "dl", "dm", "dn", "do", "dp", "dq", "dr", "ds", "dt", "du", "dv", "dw", "dx", "dy", "dz", "ea", "eb", "ec", "ed", "ee", "ef", "eg", "eh", "ei", "ej", "ek", "el", "em", "en", "eo", "ep", "eq", "er", "es", "et", "eu", "ev", "ew", "ex", "ey", "ez", "fa", "fb", "fc", "fd", "fe", "ff"] ;) a  we can deny everything, except that we have the possibility of being better. simply reflect on that. h.h. the 14th dalai lama
Hi 
On Thu, 7 Jun 2007, ara.t.howard wrote: > On Jun 7, 2007, at 5:06 AM, dbl@wobblini.net wrote: >> Hi  >> On Thu, 7 Jun 2007, Harry Kakueki wrote: >>> On 6/7/07, Revence Kalibwani <revenc@gmail.com> wrote: >>>> # That is, of course, a silly way to implemet even and odd. So, let >>>> me give you the problem >>>> # I was trying to solve. >>>> # >>>> # To generate the lettering similar to that above the spreadsheet >>>> columns, where the first >>>> # column has 'A', the second 'B' ... the twentysixth 'Z'. Then, >>>> the twentyseventh has >>>> # 'AA', the twentyeight has 'AB', and so on. This is recursive by >>>> nature. Here is what >>>> # should work: >>> I may be missing something, but.. >>> If you just want to do that then try something like this. >>> arr = [] >>> ("a".."ff").each {x arr << x} >>> p arr >> Worksaving tip for the day: >> p [*"a".."ff"] >> :) > seems a bit perlish no?
No, since you asked :) It looks like that thing in Ruby where you use the unar[r]ay operator to unarray a range :) David  Q. What is THE Ruby book for Rails developers? A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black) (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf) Q. Where can I get Ruby/Rails onsite training, consulting, coaching? A. Ruby Power and Light, LLC (http://www.rubypal.com)
>p [*"a".."ff"]
David Black's solution above looks like the best for Ruby (hey, he wrote the Ruby for Rails book :) If Ruby didn't have that ability to enumerate from "a" to "ff" (I know it does), this one would also work (in Ruby as well as in other languages like Python, with suitable changes for their different syntax): labels = [] ["a".."z"].each { c labels << c } ["a".."z"].each do c ["a".."z"].each { c2 labels << (c + c2) } end # Now do whatever you want with the array 'labels'.] ( I'm not at my PC right now, so can't check if its quite right. ) Vasudev Ram Dancing Bison Enterprises http://www.dancingbison.com
On Jun 7, 8:07 am, "Harry Kakueki" <list.p@gmail.com> wrote:
> On 6/7/07, Harry Kakueki <list.p @gmail.com> wrote: > > On 6/7/07, dbl@wobblini.net <dbl@wobblini.net> wrote: > > > Worksaving tip for the day: > > > p [*"a".."ff"] > > > :) > > > David > > >  > > > Q. What is THE Ruby book for Rails developers? > > > A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black) > > > (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf) > > > Q. Where can I get Ruby/Rails onsite training, consulting, coaching? > > > A. Ruby Power and Light, LLC (http://www.rubypal.com) > > I was going to do this. > > p ("a".."ff").each {x p x} > > Harry > Oops. > Don't need 2 p's. > ("a".."ff").each {x p x} > Harry >  > A Look into Japanese Ruby List in Englishhttp://www.kakueki.com/ Hide quoted text  >
I am not exactly sure what the OP was trying to do .. except that it has to do with Columns in Excel. It does seems to me to be fairly complicated. If this off topic, please excuse. In Excel, columns may either have a numeric format or an alpha format. Columns range for 1 .. 255 (A .. IV). Since I do quite a bit of work using Excel from Ruby via WIN32OLE, I have written a couple of helper functions to convert a numeric column value to an alpha column value and vice versa. Note that alpha columns in Excel are all caps. Here they are, I hope that someone might find them useful. # method to convert from numeric column to alpha col # accepts numeric column 1 through 256 # returns alpha column A through IV # returns empty string on invalid input def n2a_col(num_col) # verify that it in the range of 1 to 255 return nil if num_col < 1  num_col > 256 mostSD = num_col / 26 # SD = Significant Digit leastSD = num_col % 26 if leastSD == 0 mostSD = 1 leastSD = 26 end leastSA = ('A'[0] + leastSD  1 ).chr mostSA = mostSD > 0 ? ('A'[0] + mostSD  1).chr : '' mostSA + leastSA end # method to convert from alpha column to numeric col # accepts alpha column A through IV # returns numeric column 1 through 255 # returns 0 on invalid input def a2n_col(alpha_col) # to uppercase alpha_col.upcase col_size = alpha_col.size case col_size when 1 return 0 if alpha_col < 'A'  alpha_col > 'Z' return alpha_col[0]  'A'[0] + 1 when 2 return 0 if alpha_col < 'AA'  alpha_col > 'IV' return (alpha_col[0]  'A'[0] + 1) * 26 + alpha_col[1]  'A'[0] + 1 else return 0 end end
From: bbiker [mailto:ren@nc.rr.com] Sent: Thursday, June 07, 2007 12:00 PM > I am not exactly sure what the OP was trying to do .. except that it > has to do with Columns in Excel. It does seems to me to be fairly > complicated. If this off topic, please excuse.
[snip]
> # method to convert from numeric column to alpha col > # accepts numeric column 1 through 256 > # returns alpha column A through IV > # returns empty string on invalid input > def n2a_col(num_col) > # verify that it in the range of 1 to 255 > return nil if num_col < 1  num_col > 256 > mostSD = num_col / 26 # SD = Significant Digit > leastSD = num_col % 26 > if leastSD == 0 > mostSD = 1 > leastSD = 26 > end > leastSA = ('A'[0] + leastSD  1 ).chr > mostSA = mostSD > 0 ? ('A'[0] + mostSD  1).chr : '' > mostSA + leastSA > end
Not as efficient, but simpler: def n2a_col( num_col ) if (1..255).include?( num_col ) a = 'A' ( num_col1 ).times{ a = a.succ } a end end [ 0, 1, 2, 26, 27, 250, 255, 256 ].each{ n puts "%3d => %s" % [ n, n2a_col( n ).inspect ] }
#=> 0 => nil #=> 1 => "A" #=> 2 => "B" #=> 26 => "Z" #=> 27 => "AA" #=> 250 => "IP" #=> 255 => "IU" #=> 256 => nil
From: Gavin Kistner Sent: Thursday, June 07, 2007 12:10 PM
> From: bbiker [mailto:ren @nc.rr.com] > Sent: Thursday, June 07, 2007 12:00 PM > > I am not exactly sure what the OP was trying to do .. except that it > > has to do with Columns in Excel. It does seems to me to be fairly > > complicated. If this off topic, please excuse. > [snip] > > # method to convert from numeric column to alpha col > > # accepts numeric column 1 through 256 > > # returns alpha column A through IV > > # returns empty string on invalid input > > def n2a_col(num_col) > > # verify that it in the range of 1 to 255 > > return nil if num_col < 1  num_col > 256 > > mostSD = num_col / 26 # SD = Significant Digit > > leastSD = num_col % 26 > > if leastSD == 0 > > mostSD = 1 > > leastSD = 26 > > end > > leastSA = ('A'[0] + leastSD  1 ).chr > > mostSA = mostSD > 0 ? ('A'[0] + mostSD  1).chr : '' > > mostSA + leastSA > > end > Not as efficient, but simpler: > def n2a_col( num_col ) > if (1..255).include?( num_col ) > a = 'A' > ( num_col1 ).times{ a = a.succ } > a > end > end > [ 0, 1, 2, 26, 27, 250, 255, 256 ].each{ n > puts "%3d => %s" % [ n, n2a_col( n ).inspect ] > } > #=> 0 => nil > #=> 1 => "A" > #=> 2 => "B" > #=> 26 => "Z" > #=> 27 => "AA" > #=> 250 => "IP" > #=> 255 => "IU" > #=> 256 => nil
But speaking of efficiency, here's an autocaching hash that only calculates the column name once for each number. The only 'downside' is that asking for the name of column 200 the first time fills in the values for columns 199 down to the previously greatest column. COL_NAME = Hash.new{ h,n if n==1 h[n] = 'A' elsif (2..255).include?( n ) h[n] = h[n1].succ end }
[ 0, 1, 2, 26, 27, 250, 255, 256 ].each{ n puts "%3d => %s" % [ n, COL_NAME[ n ].inspect ] }
#=> 0 => nil #=> 1 => "A" #=> 2 => "B" #=> 26 => "Z" #=> 27 => "AA" #=> 250 => "IP" #=> 255 => "IU" #=> 256 => nil
From: bbiker [mailto:ren@nc.rr.com] Sent: Thursday, June 07, 2007 12:00 PM [snip] > return alpha_col[0]  'A'[0] + 1
[snip] I thought I'd point out that 'A'[0] is equivalent to ?A ..and I personally find the latter to be much more friendly. For completeness, here's how I'd write the nametonumber conversion as an autocaching hash (without the bounds tests): COL_NUM = Hash.new{ h,alpha offset = ?A  1 alpha.upcase! case alpha.size when 1 h[alpha] = alpha[0]  offset when 2 h[alpha] = ( alpha[0]  offset ) * 26 + ( alpha[1]  offset ) end
}





