Hi mental,
> Maybe think of it like foreach in TCL [ foreach i $things { ... } ],
> or the one for in Javascript [ for (var i in things) { ... } ]
> rather than for in C.
Hmm, I don't know tcl nor JS well enough.
> As a rule, I think Ruby's going to be extremely counterintuitive
> whenever you expect C-like behavior.
It worked quite well before.
> That will probably require thinking about it from a different angle.
> The "skip the next (future) element based on the current one" is an
> inherently messy concept.
Perhaps more messy than a loop without this feature, but a
next_and_skip_next_element
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?
[...]
> prev = nil
> a.each do |elt|
> puts elt unless prev == "b"
> prev = elt
> end
>
> Now, we'll imagine for the moment that Ruby has C-like for loops:
>
> a = %w(a b c d e)
>
> for ( i = 0 ; i < a.size ; i += 1 )
> puts a[i]
> i += 1 if a[i] == "b"
> end
You know that those are not the same. The first one is looking back,
the second could look forward.
> Out of curiousity, do you think either of these would be clearer?
>
> a.each_with_prev do |elt, prev|
> next if prev == "b"
> puts elt
> end
Definitely, but one can do this already with inject. Well, almost.
> A lot of Ruby's clarity comes not from being able to write things
> clearly in the "raw" language, but from being able to easily
> customize the language for your needs.
Of course, and that is what I am asking in the whole thread! Is there
a nicer way for this loop... Let's see. I have this each_with_next
now, but still I am completely unstatisfied with my loop. But I am now
convinced that I have the optimal solution, even if it the way it
looks now. And btw., I need a look-ahead for this specific purpose.
The each_with_previous was a very nice hint, thanks, even if I wasn't
able to use it. I'd probably have to create each_with_prev_and_next.
module Enumerable
def each_with_next(last=nil)
prev=nil
first=true
each do |elt|
begin
if first
first=false
next
else
yield prev,elt
end
ensure # in case of 'next'
prev = elt
end
end
yield prev,last
end
end
a=[:a, :b, :b, :c, :b, :d, :e]
skip=false
a.each_with_next do |elt,n|
if skip
skip=false
next
end
if elt==:b && n==:b
puts "double_b"
skip=true
else
puts elt
end
end
Patrick
(please, no cc:)