Style Question

Discussion in 'Ruby' started by Brian Schroeder, Sep 5, 2004.

  1. Hello everybody,

    I've got a stylistic question. I know that "the ruby way" to implement
    iterations is using .each and similar things, but sometimes I like to use

    for i in 0...n
    for j in i...n
    do something with i and for
    end
    end

    Thats nice.

    But if I want to iterate downwards the only way I found is 10.downto(0) do
    | i | end

    That seems not as intuitive as the for notation. Especially if I want ruby
    to teach algorithms to people who know how to read pseudo code, then I'd
    like something like
    > for i in 10.downto 0
    > for i in 0.upto 10


    I think this has been discussed before, but I'd like to now which style
    you use, or if I've missed the solution.

    regards,

    Brian

    PS: How is for implemented? Can I maybe teach Number.downto to return an
    object that
    is used by for to iterate like an inverse range?

    --
    Brian Schröder
    http://www.brian-schroeder.de/
     
    Brian Schroeder, Sep 5, 2004
    #1
    1. Advertising

  2. Brian Schroeder wrote:

    > Hello everybody,


    Moin!

    > I've got a stylistic question. I know that "the ruby way" to implement
    > iterations is using .each and similar things, but sometimes I like to use
    >
    > for i in 0...n
    > for j in i...n
    > do something with i and for
    > end
    > end
    >
    > Thats nice.
    >
    > But if I want to iterate downwards the only way I found is 10.downto(0) do
    > | i | end


    What about this:

    for i in (0...n).to_a.reverse
    for j in (i...n).to_a.reverse
    p [i, j]
    end
    end

    The problem with that is that it will be slow for huge ranges.

    Or maybe this:

    require 'enumerator'
    for i in (n - 1).enum_for:)downto, 0)
    for j in (n - 1).enum_for:)downto, i)
    p [i, j]
    end
    end

    Or this one:

    class Range
    def reverse_each(&block)
    unless last.respond_to?:)downto)
    raise(TypeError, "cannot reverse iterate from #{last.class}")
    end

    is_first = true
    last.downto(first) do |item|
    if is_first and exclude_end?
    is_first = false
    next
    end

    block.call(item)
    end
    end
    end

    require 'enumerator'
    for i in (0...n).enum_for:)reverse_each)
    for j in (i...n).enum_for:)reverse_each)
    p [i, j]
    end
    end

    And I think that Range should provide reverse_each in Standard Ruby...
    (There's no problem in it when using #downto -- it is only defined for
    Integers, not for Strings.)

    Regards,
    Florian Gross
     
    Florian Gross, Sep 5, 2004
    #2
    1. Advertising

  3. Hi --

    On Sun, 5 Sep 2004, Brian Schroeder wrote:

    > Hello everybody,
    >
    > I've got a stylistic question. I know that "the ruby way" to implement
    > iterations is using .each and similar things, but sometimes I like to use
    >
    > for i in 0...n
    > for j in i...n
    > do something with i and for
    > end
    > end
    >
    > Thats nice.
    >
    > But if I want to iterate downwards the only way I found is 10.downto(0) do
    > | i | end
    >
    > That seems not as intuitive as the for notation. Especially if I want ruby
    > to teach algorithms to people who know how to read pseudo code, then I'd
    > like something like
    > > for i in 10.downto 0
    > > for i in 0.upto 10

    >
    > I think this has been discussed before, but I'd like to now which style
    > you use, or if I've missed the solution.


    I would have thought that

    10.downto(0).each do |i|

    would be very pseudo-coder friendly. Have you determined for certain
    that the people you're teaching can't grasp this? You wouldn't even
    have to explain range notation :)

    > PS: How is for implemented? Can I maybe teach Number.downto to return an
    > object that
    > is used by for to iterate like an inverse range?


    You could wrap it, like this:

    class Integer
    alias olddownto downto
    def downto(x,&b)
    olddownto(x,&b) if b
    return(x..self).to_a.reverse
    end
    end


    David

    --
    David A. Black
     
    David A. Black, Sep 5, 2004
    #3
  4. "Brian Schroeder" <> schrieb im Newsbeitrag
    news:p...
    > Hello everybody,
    >
    > I've got a stylistic question. I know that "the ruby way" to implement
    > iterations is using .each and similar things, but sometimes I like to use
    >
    > for i in 0...n
    > for j in i...n
    > do something with i and for
    > end
    > end
    >
    > Thats nice.
    >
    > But if I want to iterate downwards the only way I found is 10.downto(0) do
    > | i | end
    >
    > That seems not as intuitive as the for notation. Especially if I want ruby
    > to teach algorithms to people who know how to read pseudo code, then I'd
    > like something like
    >> for i in 10.downto 0
    >> for i in 0.upto 10

    >
    > I think this has been discussed before, but I'd like to now which style
    > you use, or if I've missed the solution.
    >
    > regards,
    >
    > Brian
    >
    > PS: How is for implemented? Can I maybe teach Number.downto to return an
    > object that
    > is used by for to iterate like an inverse range?


    Even more straightforward: you can implement a range that supports both
    directions yourself plus arbitrary stepping like this:

    class Rg
    include Enumerable

    def initialize(from, to, step = sign(to - from))
    raise ArgumentError, "Invalid step #{step}" if (to - from) * step <= 0
    @from, @to, @step = from, to, step
    @to += @step - ((@to - @from) % @step)
    end

    def each
    x = @from
    until x == @to
    yield x
    x += @step
    end
    self
    end

    def sign(x)
    case
    when x > 0
    1
    when x == 0
    0
    else
    -1
    end
    end
    end

    module Kernel
    private
    def Rg(from, to, *step) Rg.new(from, to, *step) end
    end


    Then you can do this:

    >> for i in Rg 0, 10, 2
    >> puts i
    >> end

    0
    2
    4
    6
    8
    10
    => #<Rg:0x10186da0 @from=0, @step=2, @to=12>
    >> for i in Rg( 0, -10, -3 )
    >> puts i
    >> end

    0
    -3
    -6
    -9
    => #<Rg:0x101801a0 @from=0, @step=-3, @to=-12>
    >> for i in Rg 0, -10
    >> puts i
    >> end

    0
    -1
    -2
    -3
    -4
    -5
    -6
    -7
    -8
    -9
    -10
    => #<Rg:0x10199ce8 @step=-1, @to=-11, @from=0>


    Kind regards

    robert
     
    Robert Klemme, Sep 5, 2004
    #4
  5. Robert Klemme wrote:

    >> Hello everybody,


    Moin!

    >> PS: How is for implemented? Can I maybe teach Number.downto to return an
    >> object that
    >> is used by for to iterate like an inverse range?

    > Even more straightforward: you can implement a range that supports both
    > directions yourself plus arbitrary stepping like this:


    I'd prefer using an enumerator around Range#step or Fixnum#step instead.

    Here are a few small comments and suggestion about your code. Maybe they
    are useful.

    > class Rg
    > include Enumerable
    >
    > def initialize(from, to, step = sign(to - from))


    What about String Ranges?

    > raise ArgumentError, "Invalid step #{step}" if (to - from) * step <= 0
    > @from, @to, @step = from, to, step
    > @to += @step - ((@to - @from) % @step)
    > end
    >
    > def each
    > x = @from
    > until x == @to


    This is a problem -- there are Ranges that will never satisfy this
    condition. (Float ranges come to mind)

    > yield x
    > x += @step
    > end
    > self
    > end
    >
    > def sign(x)
    > case
    > when x > 0
    > 1
    > when x == 0
    > 0
    > else
    > -1
    > end
    > end


    def sign(x); x <=> 0; end

    > end


    > Kind regards
    > robert


    More regards,
    Florian Gross
     
    Florian Gross, Sep 5, 2004
    #5
  6. "Florian Gross" <> schrieb im Newsbeitrag
    news:...
    > Robert Klemme wrote:
    >
    >>> Hello everybody,

    >
    > Moin!
    >
    >>> PS: How is for implemented? Can I maybe teach Number.downto to return an
    >>> object that
    >>> is used by for to iterate like an inverse range?

    >> Even more straightforward: you can implement a range that supports both
    >> directions yourself plus arbitrary stepping like this:

    >
    > I'd prefer using an enumerator around Range#step or Fixnum#step instead.
    >
    > Here are a few small comments and suggestion about your code. Maybe they
    > are useful.
    >
    >> class Rg
    >> include Enumerable
    >>
    >> def initialize(from, to, step = sign(to - from))

    >
    > What about String Ranges?


    That was just meant as an example - implementing integer ranges. I probably
    should have pointed that out more clearly.

    >> raise ArgumentError, "Invalid step #{step}" if (to - from) * step <= 0
    >> @from, @to, @step = from, to, step
    >> @to += @step - ((@to - @from) % @step)
    >> end
    >>
    >> def each
    >> x = @from
    >> until x == @to

    >
    > This is a problem -- there are Ranges that will never satisfy this
    > condition. (Float ranges come to mind)


    Yep, the int check is missing.

    >> yield x
    >> x += @step
    >> end
    >> self
    >> end
    >>
    >> def sign(x)
    >> case
    >> when x > 0
    >> 1
    >> when x == 0
    >> 0
    >> else
    >> -1
    >> end
    >> end

    >
    > def sign(x); x <=> 0; end


    Very nice! Then we don't need sign():

    def initialize(from, to, step = ((to - from) <=> 0))

    >> end

    >
    >> Kind regards
    >> robert

    >
    > More regards,
    > Florian Gross


    EMR (even more regards)

    robert
     
    Robert Klemme, Sep 5, 2004
    #6
    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. Rob Nicholson
    Replies:
    3
    Views:
    778
    Rob Nicholson
    May 28, 2005
  2. Replies:
    0
    Views:
    2,476
  3. Replies:
    1
    Views:
    802
    Bertilo Wennergren
    Nov 24, 2003
  4. Hardeep Rakhra
    Replies:
    8
    Views:
    651
    Hardeep Rakhra
    Jan 15, 2004
  5. Ken Varn
    Replies:
    0
    Views:
    493
    Ken Varn
    Apr 26, 2004
Loading...

Share This Page