Forum: Ruby Clean way of pausing a loop?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Kyle S. (Guest)
on 2008-11-03 17:38
(Received via mailing list)
It's Monday and it's relatively early, so I apologize if this isn't
worded too well.

Is there a clean way of pausing a loop/printing status every N
iterations?  I often use ruby to examine log files in a one-off
fashion, and when dealing with files of 4-10 million lines, this is
the sort of thing that becomes important.  Small files are, obviously,
not as big of a deal.

I know I can simply do this, but it doesn't seem clean:

counter=0
n=100
foo.each do
|bar|
   counter+=1
   if (counter%n).zero?
     sleep 0.1
  end

Thanks,
       Kyle
end
Mohit S. (Guest)
on 2008-11-03 18:12
(Received via mailing list)
Kyle S. wrote:
>
> counter=0
> n=100
> foo.each do
> |bar|
>    counter+=1
>    if (counter%n).zero?
>      sleep 0.1
>   end
What's wrong with it?  I can only think that if foo allows
.each_with_index, you could avoid the counter initialization and
addition.  Can't think of anything else.

Cheers,
Mohit.
11/4/2008 | 12:09 AM.
Brian A. (Guest)
on 2008-11-03 18:55
(Received via mailing list)
Kyle S. <removed_email_address@domain.invalid> writes:

>
>        Kyle
> end

Maybe something like this?

module Enumerable
  def paused_each n, sec, pause_after=true
    counter = 0
    self.each do |e|
      yield e if pause_after
      if (counter += 1) >= n
        counter = 0
        sleep sec
      end
      yield e unless pause_after
    end
  end
end

[1,2,3,4,5,6,7].paused_each(2,2) { |e| puts e }
puts
[1,2,3,4,5,6,7].paused_each(2,2,false) { |e| puts e }
Robert K. (Guest)
on 2008-11-03 19:20
(Received via mailing list)
On 03.11.2008 16:35, Kyle S. wrote:
> It's Monday and it's relatively early, so I apologize if this isn't
> worded too well.
>
> Is there a clean way of pausing a loop/printing status every N
> iterations?  I often use ruby to examine log files in a one-off
> fashion, and when dealing with files of 4-10 million lines, this is
> the sort of thing that becomes important.  Small files are, obviously,
> not as big of a deal.

You can use ARGF.lineno when reading from ARGF:

robert@fussel ~
$ seq 1 20  | ruby -e 'ARGF.each {|l| puts "."; puts ARGF.lineno if
ARGF.lineno % 10 == 0}'
.
.
.
.
.
.
.
.
.
.
10
.
.
.
.
.
.
.
.
.
.
20


You can use IO.lineno when reading from a stream

robert@fussel ~
$ seq 1 20  | ruby -e '$stdin.each {|l| puts "."; puts $stdin.lineno if
$stdin.lineno % 10 == 0}'
.
.
.
.
.
.
.
.
.
.
10
.
.
.
.
.
.
.
.
.
.
20

Or you can use #each_with_index.

robert@fussel ~
$ seq 1 20  | ruby -e '$stdin.each_with_index {|l,i| puts "."; puts i if
i % 10 == 0}'
.
0
.
.
.
.
.
.
.
.
.
.
10
.
.
.
.
.
.
.
.
.

Or you can use $.:

robert@fussel ~
$ seq 1 20  | ruby -ne 'puts "."; puts $. if $. % 10 == 0'
.
.
.
.
.
.
.
.
.
.
10
.
.
.
.
.
.
.
.
.
.
20

I'm sure I forgot one or more variants. :-)

Cheers

  robert
Kyle S. (Guest)
on 2008-11-03 22:09
(Received via mailing list)
Hum.  Well those all work, but aren't those basically similar to what
I'm already doing?
I was hoping to somehow have a handler that would inject the logic
into an existing loop.

Oh well.

Thanks,
        Kyle
Robert K. (Guest)
on 2008-11-03 22:22
(Received via mailing list)
On 03.11.2008 21:07, Kyle S. wrote:
> Hum.  Well those all work, but aren't those basically similar to what
> I'm already doing?

They at least do not do the counting manually.  That's probably more
efficient also since counting is done in C code.

Btw, there is one more option: use each_slice. :-)

> I was hoping to somehow have a handler that would inject the logic
> into an existing loop.

I believe we have seen such a solution in this thread already.  Here's
another one

class EI
   include Enumerable

   def initialize(enum, steps, &inter)
     @enum = enum
     @steps = steps
     @inter = inter
   end

   def each
     @enum.each_with_index do |e,i|
       inter.call if i % steps == 0 && i != 0
       yield e
     end
     self
   end
end

Kind regards

  robert
This topic is locked and can not be replied to.