Skip the first invocation e.g. skip_first { foo }

On Oct 25, 10:28 pm, mortee [email protected] wrote:


consider running the above code twice would require state to be

so it can also yield

using the & notation

5.times &skip_first {|a| puts a}
1
2
3
4

So how do you pass the “real” block to the iterator then? The main
point of the iteration isn’t the code that’s skipped on the first
iteration, but the main body of the iteration. For example:

foo.each do |elem|
skip_first do
# processing to be skipped the first time
# through the loop that may or may not use
# elem
end

other important processing using elem

end

On Oct 25, 8:32 pm, “Harry K.” [email protected] wrote:

else
end
arr.each_with_index do |x,i|
p x if i !=0
end

If these are no good, then I am not understanding your question.

Correct.

Brian A. wrote:

lambda do |x|
2
# through the loop that may or may not use
# elem
end

other important processing using elem

end

Sorry, it wasn’t clear to me by this whole thread but this last post
that you wanted code which doesn’t skip elements, as well as code which
does.

The bad news is that I guess from inside the block passed to the
iterator, you have no way (at least no nice way) to keep track of the
iteration count, and make decisions based on it. You either have to call
each_with_index, and make use of the passed index, but this won’t work
with other iterators.

You might also try to set up some global variable the first time your
block is run, and then utilize that. Note that this will get tricky even
when repeatedly running loops with skipping sections - not to mention
nested ones.

So in any way, you will have to somehow estabilish what is considered
your “outermost” scope, and do some counting relative to that. (Just
consider how skipping would work if called from inside a nested loop.
Will it skip the first n iteration of the outer loop, or the inner one?)

All in all, you’ll almost certainly have to set up your skipping and
non-skipping code blocks while still outside the loop itself. This is
what e.g. the above proposed skip_first method would do, just hiding the
variable initialization part from the caller.

It could e.g. be extended to accept two blocks: one which skips the
first n iterations, and one wich does not - but this wouldn’t be elegant
any more, and also the local variables would be separate in the two
blocks.

What you could still perhaps do is trying to tag your calling contexts
as the basis for skipping, and then from inside the loop body try to
refer to it. Like going upwards the calling stack using
Binding.of_caller, and look for a specially named local variable which
is set up by the former facility, and use that as a reference for how
many times your block has been called. Something like:

collection.some_iterator &skip_context do

this sets up the context with some counter variable


skip_first {
# whithin the skip_first method the above mentioned variable isn’t
# visible, but it may be sought for using some stack-traversing
# trickery

}

end

mortee

2007/10/26, mortee [email protected]:

_iteration = 0
1
# processing to be skipped the first time
# through the loop that may or may not use
# elem
end

other important processing using elem

end

Sorry, it wasn’t clear to me by this whole thread but this last post
that you wanted code which doesn’t skip elements, as well as code which
does.

Oh, that eluded me as well. In that case it’s certainly best to just
use #each_with_index and use the index as you said.

The bad news is that I guess from inside the block passed to the
iterator, you have no way (at least no nice way) to keep track of the
iteration count, and make decisions based on it. You either have to call
each_with_index, and make use of the passed index, but this won’t work
with other iterators.

It does, if you use Enumerator:

17:26:33 ~$ irb -r enumerator
irb(main):001:0> %w{foo bar baz}.to_enum(:each_with_index).
irb(main):002:0* map {|e,i| i % 2 == 0 ? e : :empty}
=> [“foo”, :empty, “baz”]
irb(main):003:0>

You might also try to set up some global variable the first time your
block is run, and then utilize that. Note that this will get tricky even
when repeatedly running loops with skipping sections - not to mention
nested ones.

I would not go down that road either.

So in any way, you will have to somehow estabilish what is considered
your “outermost” scope, and do some counting relative to that. (Just
consider how skipping would work if called from inside a nested loop.
Will it skip the first n iteration of the outer loop, or the inner one?)

All in all, you’ll almost certainly have to set up your skipping and
non-skipping code blocks while still outside the loop itself. This is
what e.g. the above proposed skip_first method would do, just hiding the
variable initialization part from the caller.

Frankly, I believe this shows it’s all not worth the effort. Checking
the provided iteration counter is straightforward and easy to read and
understand.

Kind regards

robert

On 26.10.2007 17:50, mortee wrote:

irb(main):001:0> %w{foo bar baz}.to_enum(:each_with_index).
irb(main):002:0* map {|e,i| i % 2 == 0 ? e : :empty}
=> [“foo”, :empty, “baz”]
irb(main):003:0>

Thanks, this is nice - I haven’t known it existed. However,
unfortunately it’s less “elegant” than simply using the iterator itself,
and enclosing parts of the loop body in skip_first{…}

Obviously tastes differ. :slight_smile: Personally I find the effort you have to
invest to get a correct working and failure safe version of skip_first
extremely inelegant for a problem which has a much simpler solution.

Kind regards

robert

Robert K. wrote:

irb(main):001:0> %w{foo bar baz}.to_enum(:each_with_index).
irb(main):002:0* map {|e,i| i % 2 == 0 ? e : :empty}
=> [“foo”, :empty, “baz”]
irb(main):003:0>

Thanks, this is nice - I haven’t known it existed. However,
unfortunately it’s less “elegant” than simply using the iterator itself,
and enclosing parts of the loop body in skip_first{…}

mortee

On Oct 26, 2007, at 7:15 AM, Brian A. wrote:

cfp:~ > cat a.rb
block = lambda{ block = lambda{ puts ‘foo’ } }
3.times{ block.call }

Clever :slight_smile: I’ve used a similar technique in JavaScript, but I don’t
like defining the code outside of the loop, and it’s also not as clear
as other solutions IMO.

it’s just a building block… to generalize your idea, now that you
sketched it out more fully, i’d probably do

cfp:~ > cat a.rb
class Proc
def skip(n, i = 0) lambda{|*a| call *a if (i += 1) > n } end
end
class Object
def skip(n, &block) block.skip n end
end

3.times &skip(1){ puts ‘foo’ }

%w[ a b c ].each_with_index &skip(2){|element, index| p element, index}

cfp:~ > ruby a.rb
foo
foo
“c”
2

a @ http://codeforpeople.com/

2007/10/26, Brian A. [email protected]:

available = whois #{domain} =~ /No match for “#{domain.upcase}”./
puts “#{domain} is #{available ? ‘’ : ‘NOT’} available”
end

Hi Brian, sorry for the late reply. Here’s something with a simpler
calling syntax:

module SkipN
@callers = Hash.new(0)
def self.skip(n = 1, key = caller.first)
yield if (@callers[key] += 1) > n
end
def self.skip_first
skip(1, caller.first) { yield }
end
end

Usage:

3.times do |i|
puts “start #{i}”
SkipN.skip_first { puts “*** #{i} ***” }
puts “end #{i}”
end

puts

%w[a b c].each_with_index do |e, i|
puts “start #{e} at #{i}”
SkipN.skip(2) { puts “*** #{e} at #{i} ***” }
puts “end #{e} at #{i}”
end

Output:

start 0
end 0
start 1
*** 1 ***
end 1
start 2
*** 2 ***
end 2

start a at 0
end a at 0
start b at 1
end b at 1
start c at 2
*** c at 2 ***
end c at 2

Note that this only works in simple cases. For example it’s not
thread-safe.

Regards,
Pit

On 10/26/07, ara.t.howard [email protected] wrote:

class Object
def skip(n=1,&block)
lambda{|*a| block.call *a if ( n -= 1 ) < 0 }
end
end

May I suggest this simplification or did I miss a hidden functionality?

Cheers
Robert

On 10/29/07, Pit C. [email protected] wrote:

end

end

Bravo!

Note that this only works in simple cases. For example it’s not thread-safe.

It also leaks memory since the @callers class instance variable never
has the keys deleted.

But cool nonetheless.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

2007/10/29, Brian A. [email protected]:

end

Output:

i is 1

i is 0
i is 1

Ah, but you didn’t show us this use case yet, didn’t you?

Not that I would use or recommend the following code, but
nethertheless here’s a more powerful (albeit slower) version:

module SkipN

@skips = Hash.new(0)
@min_levels = Hash.new(0)
@level = 0

@trace = lambda do |event, file, line, id, binding, classname|
  case event
  when "call", "c-call"
    @level += 1
  when "return", "c-return"
    @level -= 1
    @min_levels.each do |key, min|
      @min_levels[key] = @level if @level < min
    end
  end
end

def self.skip(n = 1, reset_levels = 1, key = caller.first)
  set_trace_func(nil)
  @level -= 1
  min = @min_levels[key]
  @skips[key] = 0 if min > 0 and @level - min > reset_levels
  yield if (@skips[key] += 1) > n
  @min_levels[key] = @level
  set_trace_func(@trace)
end

def self.skip_first(reset_levels = 1)
  skip(1, reset_levels + 1, caller.first) { yield }
end

set_trace_func(@trace)

end

Usage:

3.times do |i1|
3.times do |i2|
3.times do |i3|
SkipN.skip_first(3) { puts “level 3, indexes #{i1}#{i2}#{i3}” }
SkipN.skip_first(2) { puts “level 2, indexes #{i1}#{i2}#{i3}” }
SkipN.skip_first(1) { puts “level 1, indexes #{i1}#{i2}#{i3}” }
end
end
end

The level 3 code only skips the first iteration with indexes 000.
The level 2 code skips iterations with indexes *00.
The level 1 code skips iterations with indexes **0.

But specifying the “reset level” in the inner loop looks as too much
magic to me. It’s much more readable if you explicitly reset the
counter at the appropriate places.

Regards,
Pit

On Oct 29, 11:40 am, “Pit C.” [email protected] wrote:

ARGV.each do |domain|
def self.skip(n = 1, key = caller.first)
puts “start #{i}”
end
Very imaginative - thanks for the post :slight_smile: It has a problem that will
exclude it (below), but I always like to see different ways of
thinking in Ruby. I don’t see a possible solution without
initialization outside the loop.

2.times do
2.times do |i|
SkipN.skip_first { puts “i is #{i}” }
end
puts ‘-’*10
end

Output:

i is 1