[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: increasing counter whithin loop?

Martin DeMello

12/7/2005 9:47:00 AM

Patrick Gundlach <clr8.10.randomuser@spamgourmet.com> wrote:
> Hello again,
>
>
> thanks for the answers. I have been very unclear what I wanted, but
> Malte, Guy and JEGII seemed to have read my mind.
>
> a=%w( a b b d b e )
>
> a.each_with_index do |x, i|
> next if x == "b" and a[i - 1] == "b"
> if x=="b" and a[i+1]=="b"
> puts "double b"
> else
> puts x
> end
> end

I'd use Gary Watson's method, and cache the last seen element, rather
than rely upon the index (e.g. if you use a stream rather than an array,
you no longer have access to a[i-i]).

martin
24 Answers

Trans

12/7/2005 1:33:00 PM

0

Maybe I missed something.

last = nil
%w( a b c d e ).select { |e| r = last != 'b' ; last = e ; r }

T.

Patrick Gundlach

12/7/2005 3:48:00 PM

0


> Maybe I missed something.

You missed to read my mind; my explanation was very unclear. I wanted
to have something like

"if two 'b' are consecutive, output 'double b' and continue with the
element behind the second".

'a' 'b' 'b' 'c' 'b' 'd'

->

'a' 'double b' 'c' 'b' 'd'

This is why I thought

for i in sequence
if sequence[i]=='b' and sequence[i+1]=='b'
output 'double b'
# increase i, so that the second 'b' won't be seen by the for-loop
# but ruby won't let me!?
# i += 1 does nothing
else
output sequence[i]
end
end

would work, but I can't change the i in the for-loop. This is a pity!

Patrick

MenTaLguY

12/7/2005 5:52:00 PM

0

Quoting Patrick Gundlach <clr9.10.randomuser@spamgourmet.com>:

> This is why I thought
>
> for i in sequence
> if sequence[i]=='b' and sequence[i+1]=='b'
> output 'double b'
> # increase i, so that the second 'b' won't be seen by the
> for-loop
> # but ruby won't let me!?
> # i += 1 does nothing
> else
> output sequence[i]
> end
> end
>
> would work, but I can't change the i in the for-loop. This is a
> pity!

It's probably helpful to realize that Ruby has no for-loop in the
traditional sense. The above is equivalent to:

sequence.each do |i|
if sequence[i]=='b' and sequence[i+1]=='b'
output 'double b'
# increase i, so that the second 'b' won't be seen by the
for-loop
# but ruby won't let me!?
# i += 1 does nothing
else
output sequence[i]
end
end

Written this way, it's probably more obvious why incrementing i
doesn't do what you had expected.

-mental


Kevin Brown

12/7/2005 7:23:00 PM

0

On Wednesday 07 December 2005 11:51, mental@rydia.net wrote:
> Quoting Patrick Gundlach <clr9.10.randomuser@spamgourmet.com>:
> > This is why I thought
> >
> > for i in sequence
> > if sequence[i]=='b' and sequence[i+1]=='b'
> > output 'double b'
> > # increase i, so that the second 'b' won't be seen by the
> > for-loop
> > # but ruby won't let me!?
> > # i += 1 does nothing
> > else
> > output sequence[i]
> > end
> > end
> >
> > would work, but I can't change the i in the for-loop. This is a
> > pity!
>
> It's probably helpful to realize that Ruby has no for-loop in the
> traditional sense. The above is equivalent to:
>
> sequence.each do |i|
> if sequence[i]=='b' and sequence[i+1]=='b'
> output 'double b'
> # increase i, so that the second 'b' won't be seen by the
> for-loop
> # but ruby won't let me!?
> # i += 1 does nothing
> else
> output sequence[i]
> end
> end
>
> Written this way, it's probably more obvious why incrementing i
> doesn't do what you had expected.
>
> -mental

If you're really tied to the traditional for loop, you can use a while loop
and do the increment yourself at the end of the loop, but usually you find a
better way to do it in Ruby that doesn't involve going through the chars one
at a time, and that's why we rarely use the for construct.


Patrick Gundlach

12/7/2005 8:56:00 PM

0




> It's probably helpful to realize that Ruby has no for-loop in the
> traditional sense. The above is equivalent to:
>
> sequence.each do |i|
> [...]
> end
>
> Written this way, it's probably more obvious why incrementing i
> doesn't do what you had expected.


Yes, but when writing 'for i in x ... end' I'd expect a for-loop :-)
It would be really nice to be able to increase the counter from within
the loop. I somewhat expected that to work, I can't tell you why.
Perhaps that is what I was used to in other languages?

Patrick

Patrick Gundlach

12/7/2005 9:14:00 PM

0


[...]

> If you're really tied to the traditional for loop, you can use a while loop
> and do the increment yourself at the end of the loop, but usually you find a
> better way to do it in Ruby that doesn't involve going through the chars one
> at a time, and that's why we rarely use the for construct.

That is exactly what I am trying to find. I have a list (Array) of
different elements, which I want to render below each other, except
when there are two elements of type 'b', they can be put next to each
other. So I think I need a check like 'if this element is == 'b' and
next element is also == 'b', then render them next to each other. This
rendering has to be known in advance, so I can't use information if
the last element is of type 'b' (with the second occurance of 'b').

Of course, I can write a while loop, but this would be

a) setting some counter to 0
b) accessing the elements via [] (index)
c) checking on counter <=> sequence.length

all which are acceptable, but don't look like the nice ruby builtins
that I am used to. The

sequence.each do |element|
....
end

would be nice, but I understand that there is no
'skip_the_next_element'-method. So the next nicer attempt would be

for counter in 0...element.size
# ...
increase_counter_by_one_to_skip_one_interation
end

But - contradicting my intuition - doesn't seem to work/exist. So I
have to stick to an ugly while loop.... ;-) So my question is: did I
miss something? Is there any reason why we can't manipulate the
counter within the loop?

Patrick

Kevin Brown

12/7/2005 10:24:00 PM

0

On Wednesday 07 December 2005 16:07, Patrick Gundlach wrote:
> [...]
>
> > If you're really tied to the traditional for loop, you can use a while
> > loop and do the increment yourself at the end of the loop, but usually
> > you find a better way to do it in Ruby that doesn't involve going through
> > the chars one at a time, and that's why we rarely use the for construct.
>
> That is exactly what I am trying to find. I have a list (Array) of
> different elements, which I want to render below each other, except
> when there are two elements of type 'b', they can be put next to each
> other. So I think I need a check like 'if this element is == 'b' and
> next element is also == 'b', then render them next to each other. This
> rendering has to be known in advance, so I can't use information if
> the last element is of type 'b' (with the second occurance of 'b').
>
> Of course, I can write a while loop, but this would be
>
> a) setting some counter to 0
> b) accessing the elements via [] (index)
> c) checking on counter <=> sequence.length
>
> all which are acceptable, but don't look like the nice ruby builtins
> that I am used to. The
>
> sequence.each do |element|
> ....
> end
>
> would be nice, but I understand that there is no
> 'skip_the_next_element'-method. So the next nicer attempt would be
>
> for counter in 0...element.size
> # ...
> increase_counter_by_one_to_skip_one_interation
> end
>
> But - contradicting my intuition - doesn't seem to work/exist. So I
> have to stick to an ugly while loop.... ;-) So my question is: did I
> miss something? Is there any reason why we can't manipulate the
> counter within the loop?

No, you can manipulate the counter just fine, just that it won't persist for
the next iteration of the count. This is because ruby is providing the i for
you, but not actually checking it to know where it is, or when it's done,
unlike similarly worded constructs in C etc.

How about something like:

irb(main):008:0> "abbcdeef".gsub(/(\w)\1/) { |match|
irb(main):009:1* " double #{match[0, 1]} "
irb(main):010:1> }
=> "a double b cd double e f"


MenTaLguY

12/7/2005 11:08:00 PM

0

Quoting Patrick Gundlach <clr9.10.randomuser@spamgourmet.com>:

> sequence.each do |element|
> ....
> end
>
> would be nice, but I understand that there is no
> 'skip_the_next_element'-method. So the next nicer attempt would
> be
>
> for counter in 0...element.size
> # ...
> increase_counter_by_one_to_skip_one_interation
> end
>
> But - contradicting my intuition - doesn't seem to work/exist. So
> I have to stick to an ugly while loop.... ;-) So my question is:
> did I miss something?

There's really no difference between:

for counter in 0...element_size
...
end

and

(0...element_size).each do |counter|
...
end

Both call Range#each with the given block.

> Is there any reason why we can't manipulate the counter within
> the loop?

'counter' isn't actually a counter. It's just a parameter of the
block given to Range#each. While there's probably a real counter
behind the scenes somewhere, it's not exposed to you.

90% of the time you don't need counters or while loops, though.
Even here, there's nothing preventing you from doing e.g.:

skip = false
sequence.each do |element|
if skip
skip = false
next
end
...
# set skip to true to skip the next iteration
...
end

or alternately:

skip = false
sequence.each do |element|
unless skip
...
# set skip to true to skip the next iteration
...
end
skip = false
end

-mental


Patrick Gundlach

12/7/2005 11:52:00 PM

0

Hi Kevin,

[for i in ..... end ]

> No, you can manipulate the counter just fine, just that it won't persist for
> the next iteration of the count. This is because ruby is providing the i for
> you, but not actually checking it to know where it is, or when it's done,
> unlike similarly worded constructs in C etc.

That (last part of the sentence) is exactly what confused me. Nobody
else thinks that this persistance would be useful?


Patrick

Patrick Gundlach

12/7/2005 11:57:00 PM

0


[...]

> There's really no difference between:
>
> for counter in 0...element_size
> ...
> end
>
> and
>
> (0...element_size).each do |counter|
> ...
> end

OK, then it makes sense that one cannot manipulate counter. But IMO it
is not intuitive (POLS ;-)) that the counter in the for-loop can't be
changed.


> 90% of the time you don't need counters or while loops, though.
> Even here, there's nothing preventing you from doing e.g.:
>
> skip = false
> sequence.each do |element|
> if skip
> skip = false
> next
> end
> ...
> # set skip to true to skip the next iteration
> ...
> end

Yes, sure, but now it is getting ugly again. I am not looking for any
way to work, but to find a readable, beautiful and ruby-like piece of
code.

Patrick