Iterators and blocks question

Discussion in 'Ruby' started by Bharat Ruparel, Feb 8, 2007.

  1. I am new to ruby and am trying to learn my way around it. I saw the
    following example somewhere on the net to read a file line by line and
    list it to the console:

    IO.foreach("test.txt") {|line| puts line}

    This works great. However, I am trying to take the next step(s). For
    starters, I would like to modify the above code such that it lets me
    prepend the line numbers to each line as it is listed to the console.
    Something similar to the listing below for example:

    1. First line from the file..
    2. Second line from the file...
    ..
    ..
    12. Last line from the file.

    What is the Ruby idiom for doing this? Using the iterator and the code
    block?

    Thanks in advance.
    Regards,

    Bharat

    --
    Posted via http://www.ruby-forum.com/.
    Bharat Ruparel, Feb 8, 2007
    #1
    1. Advertising

  2. Bharat Ruparel wrote:
    > I am new to ruby and am trying to learn my way around it. I saw the
    > following example somewhere on the net to read a file line by line and
    > list it to the console:
    >
    > IO.foreach("test.txt") {|line| puts line}
    >
    > This works great. However, I am trying to take the next step(s). For
    > starters, I would like to modify the above code such that it lets me
    > prepend the line numbers to each line as it is listed to the console.
    > Something similar to the listing below for example:
    >
    > 1. First line from the file..
    > 2. Second line from the file...
    > ..
    > ..
    > 12. Last line from the file.
    >
    > What is the Ruby idiom for doing this? Using the iterator and the code
    > block?
    >
    > Thanks in advance.
    > Regards,
    >
    > Bharat
    >
    >

    counter = 1
    IO.foreach("test.txt") {|line| puts "#{counter}. #{line}"; counter += 1}
    Timothy Hunter, Feb 8, 2007
    #2
    1. Advertising

  3. Bharat Ruparel, Feb 8, 2007
    #3
  4. Bharat Ruparel

    oinkoink Guest

    On Feb 8, 2:36 pm, Bharat Ruparel <> wrote:
    > IO.foreach("test.txt") {|line| puts line}
    >
    > This works great. However, I am trying to take the next step(s). For
    > starters, I would like to modify the above code such that it lets me
    > prepend the line numbers to each line as it is listed to the console.
    > Something similar to the listing below for example:
    >
    > 1. First line from the file..
    > 2. Second line from the file...
    > .
    > .
    > 12. Last line from the file.


    > What is the Ruby idiom for doing this? Using the iterator and the code
    > block?


    > Thanks in advance.
    > Regards,
    > Bharat


    > Posted viahttp://www.ruby-forum.com/.


    Namaste Bharat.
    You might try something like
    require 'mathn'
    width = (Math.log((rl = IO.readlines("test.txt")).length)/
    Math.log(10)).floor + 1
    rl.each_with_index{ |line, k| print "%#{width}d. " % k + line}

    Regards, Bret
    oinkoink, Feb 8, 2007
    #4
  5. Bharat Ruparel

    oinkoink Guest

    On Feb 8, 3:25 pm, "oinkoink" <> wrote:
    > require 'mathn'
    > width = (Math.log((rl = IO.readlines("test.txt")).length)/
    > Math.log(10)).floor + 1
    > rl.each_with_index{ |line, k| print "%#{width}d. " % k + line}


    Following up to myself, the idea is to keep from indenting the lines
    differently
    every time the line number passes a power of 10.
    Regards, Bret
    oinkoink, Feb 9, 2007
    #5
  6. On Feb 8, 2007, at 7:05 PM, oinkoink wrote:
    > On Feb 8, 3:25 pm, "oinkoink" <> wrote:
    >> require 'mathn'
    >> width = (Math.log((rl = IO.readlines("test.txt")).length)/
    >> Math.log(10)).floor + 1
    >> rl.each_with_index{ |line, k| print "%#{width}d. " % k + line}

    >
    > Following up to myself, the idea is to keep from indenting the lines
    > differently
    > every time the line number passes a power of 10.
    > Regards, Bret


    width = (rl = IO.readlines("test.txt")).length.to_s.length
    format = "%2$#{width}d: %1$s" # see Kernel#sprintf
    rl.each_with_index { |*ary| ary[1] += 1; print format % ary }

    The ary[1]+=1 part is to make the numbers 1-based. If you're OK with
    the zero, leave it out. Of course, if you want to start with 1, it
    makes more sense to do:

    number = 0
    rl.each { |line| number += 1; print format % [ line, number ] }

    or

    rl.each_with_index { |line,number| print format % [ line, number
    +1 ] }

    But then you could go back to the simpler format string and swap the
    order of the args yourself.

    -Rob

    Rob Biedenharn http://agileconsultingllc.com
    Rob Biedenharn, Feb 9, 2007
    #6
  7. Bharat Ruparel, Feb 9, 2007
    #7
  8. How can one go about looking up this sort of information online? I like
    to do a bit of my homework before asking the question except I don't
    know where the library is....

    --
    Posted via http://www.ruby-forum.com/.
    Bharat Ruparel, Feb 9, 2007
    #8
  9. On Feb 8, 2007, at 11:03 PM, Bharat Ruparel wrote:

    > How can one go about looking up this sort of information online? I
    > like
    > to do a bit of my homework before asking the question except I don't
    > know where the library is....


    Try this at your prompt:

    ri Kernel#sprintf

    ri IO.readlines

    and so on. If you don't have a copy of the pickaxe (Programming
    Ruby; http://pragmaticprogrammer.com/titles/ruby/index.html) then
    that should be your first book.

    Online of course you have:

    The Ruby Home Page: http://www.ruby-lang.org/en/

    from which you have links to *much* more than it would be worth my
    repeating.

    -Rob

    Rob Biedenharn http://agileconsultingllc.com
    Rob Biedenharn, Feb 9, 2007
    #9
  10. On 08.02.2007 23:44, Timothy Hunter wrote:
    > Bharat Ruparel wrote:


    > counter = 1
    > IO.foreach("test.txt") {|line| puts "#{counter}. #{line}"; counter += 1}


    An injectified version of this:

    require 'enumerator'
    IO.to_enum:)foreach, "test.txt").inject(0) do |counter, line|
    puts "#{counter}. #{line}"
    counter + 1
    end

    :)

    robert
    Robert Klemme, Feb 9, 2007
    #10
  11. On Fri, Feb 09, 2007 at 01:18:10PM +0900, Rob Biedenharn wrote:
    > and so on. If you don't have a copy of the pickaxe (Programming
    > Ruby; http://pragmaticprogrammer.com/titles/ruby/index.html) then
    > that should be your first book.


    The old version is available to read on-line:
    http://www.rubycentral.com/book/

    It was written for Ruby 1.6, but it basically applies to Ruby 1.8 as well
    (it just doesn't document the additions :) And if you like it, as you
    probably will, you can then buy the paper or PDF version of the new one.

    > Online of course you have:
    >
    > The Ruby Home Page: http://www.ruby-lang.org/en/


    and also:
    http://wiki.rubygarden.org/Ruby
    Brian Candler, Feb 9, 2007
    #11
  12. Thanks Robert,
    Tim Hunter's solution seems most straightforward to me. Which is:
    counter = 1
    IO.foreach("test.txt") {|line| puts "#{counter}. #{line}"; counter += 1}

    The solution that you present:
    require 'enumerator'
    IO.to_enum:)foreach, "test.txt").inject(0) do |counter, line|
    puts "#{counter}. #{line}"
    counter + 1
    end

    Seems like a good one too, except more indirect. When would you
    recommend using one over another? Or is it largely a matter of taste?
    Also, why do you have to "require" the enumerator module here whereas
    Tim's solution didn't. I did a search on "ri IO" and it shows that IO
    includes enumerable (it is not enumerator, I know). Also it shows that
    foreach is a class method for IO class whereas I could not find anything
    on to_enum. Is there a way to get RoR style online API docs for Ruby?
    I find "ri" a bit primitive.

    Bharat

    --
    Posted via http://www.ruby-forum.com/.
    Bharat Ruparel, Feb 9, 2007
    #12
  13. On 09.02.2007 15:39, Bharat Ruparel wrote:
    > Thanks Robert,
    > Tim Hunter's solution seems most straightforward to me. Which is:
    > counter = 1
    > IO.foreach("test.txt") {|line| puts "#{counter}. #{line}"; counter += 1}
    >
    > The solution that you present:
    > require 'enumerator'
    > IO.to_enum:)foreach, "test.txt").inject(0) do |counter, line|
    > puts "#{counter}. #{line}"
    > counter + 1
    > end
    >
    > Seems like a good one too, except more indirect. When would you
    > recommend using one over another? Or is it largely a matter of taste?


    Yes. And there is a ton of other equally good solutions.

    > Also, why do you have to "require" the enumerator module here whereas
    > Tim's solution didn't.


    Because the module is not loaded by default. (IIRC that will change /
    has changed in Ruby 1.9).

    > I did a search on "ri IO" and it shows that IO
    > includes enumerable (it is not enumerator, I know). Also it shows that
    > foreach is a class method for IO class whereas I could not find anything
    > on to_enum. Is there a way to get RoR style online API docs for Ruby?
    > I find "ri" a bit primitive.


    I usually use http://www.ruby-doc.org/

    For example

    http://www.ruby-doc.org/core/classes/Enumerable/Enumerator.html

    Kind regards

    robert
    Robert Klemme, Feb 9, 2007
    #13
  14. Bharat Ruparel, Feb 9, 2007
    #14
    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. Arjen
    Replies:
    3
    Views:
    429
    Scott Allen
    Feb 27, 2005
  2. Marcin Kaliciñski

    Iterators and reverse iterators

    Marcin Kaliciñski, May 8, 2005, in forum: C++
    Replies:
    1
    Views:
    478
    Kai-Uwe Bux
    May 8, 2005
  3. , India
    Replies:
    10
    Views:
    1,060
    James Kanze
    Aug 8, 2009
  4. matt
    Replies:
    1
    Views:
    244
    George Ogata
    Aug 6, 2004
  5. Steven Taylor
    Replies:
    9
    Views:
    239
    Brian Candler
    Apr 27, 2009
Loading...

Share This Page