From: MenTaLguY Date: 2005-12-08T21:28:24+09:00 Subject: Re: increasing counter whithin loop? --=-9QO+RI5iGfRZnSDf++85 Content-Type: text/plain Content-Transfer-Encoding: quoted-printable On Thu, 2005-12-08 at 18:07 +0900, Patrick Gundlach wrote: > Perhaps more messy than a loop without this feature, but a=20 >=20 > next_and_skip_next_element >=20 > should be perfectly clear to a reader. I mean, if we have > 'complicated' constructs such as 'inject', we will be able to cope > with 'skip_next_element', won't we? I think you could implement something like that via a customized each and a catch/throw, yes. It'd be a bit involved but certainly doable. > [ snip ] > > You know that those are not the same. The first one is looking back, > the second could look forward. I guess I misunderstood the goal. I was going for "the cleanest way to skip elements following those satisfying some condition", rather than "the cleanest way to skip elements following those satisfying some condition". :) But from your new example it's apparent that you really do want iteration-with-lookahead (or an equivalent), and the ability to consume more than one input item at a time. That sounds suspiciously like parsing a grammar... > module Enumerable > def each_with_next(last=3Dnil) > prev=3Dnil > first=3Dtrue > each do |elt| > begin > if first > first=3Dfalse > next > else > yield prev,elt > end > ensure # in case of 'next' > prev =3D elt > end > end > yield prev,last > end > end It's a subtle detail, but you'd probably want to wrap that yield prev,last in a 1.times {} so retry and next work as expected. You've also got to handle break specially, and handle the empty case. module Enumerable def each_with_next(last=3Dnil) prev =3D nil first =3D true skip_last =3D true # skip last iteration if empty each do |elt| skip_last =3D true # skip last iteration if 'break' used begin if first first =3D false next else yield prev, elt end ensure # in case of 'next' prev =3D elt end skip_last =3D false # 'break' wasn't used this time around end 1.times { yield prev, last } unless skip_last end end Messing with the future makes messy code. At least it's all confined in one place. Ah, I did just notice that 'retry' won't work with this, as both 'next' and 'retry' will hit the ensure clause. That might not be a problem for your purposes, though. I notice a lot of things (like IO#each) don't really support retry either. Just for fun, here is an alternate approach for the lookahead. You'll probably recognize it as the C-like solution, dressed up a bit. a =3D %w(a b b c b d e).map { |s| s.intern } ArrayStream.new(a).each do |elt| if elt =3D=3D :b && s.la =3D=3D :b puts "double_b" s.skip else puts elt end end Given: class ArrayStream include Enumerable def initialize( array ) @array =3D array @pos =3D 0 end def empty? @pos >=3D @array.size end def get pos =3D @pos @pos +=3D 1 @array[pos] end def la(offset=3D1) @array[@pos+offset] end def skip(offset=3D1) @pos +=3D offset end def each # 'retry' won't retry, but then that # doesn't work for IO#each either yield get until empty? end end You know, there has GOT to be a simpler way to do this... :) What's the actual problem you're trying to solve? I'll bet there's a more "outside the box" solution. As I said, you're basically parsing a simple grammar: GRAMMAR :=3D ( DOUBLE_B | LETTER )* DOUBLE_B :=3D 'b' 'b' LETTER :=3D 'a' | 'b' | 'c' | 'd' | ... | 'z' If your input is strings, regexps are the tool for this (it's a regular grammar). If it's something else, you still might want to bring some parsing-related techniques and/or libraries to bear. Of course, if your real problem is not much more complex than your example, I'd say go with the index variable and while loop. :P -mental --=-9QO+RI5iGfRZnSDf++85 Content-Type: application/pgp-signature; name=signature.asc Content-Description: This is a digitally signed message part -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) iD8DBQBDmCKEcUNIGiXCc4MRAnyxAKCCp0OZf1zCXDUnrOJSqGakS6hBUgCgsaWy 1wuHltkBAPsqVFJc7a5OTQ8= =NKcQ -----END PGP SIGNATURE----- --=-9QO+RI5iGfRZnSDf++85--