I'd like to output the sequence "a b d e", by testing if the current
element is == "b" then skip the next element and continue the loop. The
obvious solution doesn't look rubyish to me, how could I use the first
or second attempt to get the desired solution?
Patrick
···
--------------------------------------------------
a=%w( a b c d e )
# incorrect, outputs "a b c d e"
0.upto(a.size - 1) do |i|
puts a[i]
if a[i]=="b"
# skip next element
# but i won't get affected
i += 1
end
end
# incorrect, outputs "a b c d e"
for i in 0...a.size
puts a[i]
if a[i]=="b"
# skip next element
# but i won't get affected
i += 1
end
end
# incorrect, outputs nothing... is there a next_next ?
a.each do |elt|
puts elt
if elt=="b"
# skip next element
# ??
end
end
# this one works, but is ugly
i=0
while i < a.size
puts a[i]
if a[i]=="b"
# skip next element
i += 1
end
i += 1
end
I'd like to output the sequence "a b d e", by testing if the current
element is == "b" then skip the next element and continue the loop.
The obvious solution doesn't look rubyish to me, how could I use the
first or second attempt to get the desired solution?
Patrick
--------------------------------------------------
a=%w( a b c d e )
I'd like to output the sequence "a b d e", by testing if the current
element is == "b" then skip the next element and continue the loop. The
obvious solution doesn't look rubyish to me, how could I use the first
or second attempt to get the desired solution?
# Zipped to ensure i is uniquely index()ed
# Also makes sure use array non-destructively
zip = array.zip
for i in zip
if i[0] == :skip
zip.delete_at(zip.index(i) + 1)
else
puts i[0]
end
end
Output:
1
2
3
···
--
Neil Stevens - neil@hakubi.us
'A republic, if you can keep it.' -- Benjamin Franklin
p a.select {|x| if temp == "b" then temp = nil; next end; temp = x;true}
outputs
["a", "b", "d", "e"]
Probably could be cleaner.
Patrick Gundlach wrote:
···
Hi,
a very basic question...
I'd like to output the sequence "a b d e", by testing if the current
element is == "b" then skip the next element and continue the loop. The
obvious solution doesn't look rubyish to me, how could I use the first
or second attempt to get the desired solution?
Patrick
--------------------------------------------------
a=%w( a b c d e )
# incorrect, outputs "a b c d e"
0.upto(a.size - 1) do |i|
puts a[i]
if a[i]=="b"
# skip next element
# but i won't get affected
i += 1
end
end
# incorrect, outputs "a b c d e"
for i in 0...a.size
puts a[i]
if a[i]=="b"
# skip next element
# but i won't get affected
i += 1
end
end
# incorrect, outputs nothing... is there a next_next ?
a.each do |elt|
puts elt
if elt=="b"
# skip next element
# ??
end
end
# this one works, but is ugly
i=0
while i < a.size
puts a[i]
if a[i]=="b"
# skip next element
i += 1
end
i += 1
end
Maybe I'm just being thick, but wouldn't it just be easier (and much
closer to what you are actually trying to do) to say
["a", "b", "c", "d", "e"].each do |x|
puts x unless x == "c"
end
I'll admit I'm also new to Ruby but isn't the above the more "rubyish"
way to achieve what you're trying to do?
···
On 12/5/05, Patrick Gundlach <clr9.10.randomuser@spamgourmet.com> wrote:
Hi,
a very basic question...
I'd like to output the sequence "a b d e", by testing if the current
element is == "b" then skip the next element and continue the loop. The
obvious solution doesn't look rubyish to me, how could I use the first
or second attempt to get the desired solution?
Patrick
--------------------------------------------------
a=%w( a b c d e )
# incorrect, outputs "a b c d e"
0.upto(a.size - 1) do |i|
puts a[i]
if a[i]=="b"
# skip next element
# but i won't get affected
i += 1
end
end
# incorrect, outputs "a b c d e"
for i in 0...a.size
puts a[i]
if a[i]=="b"
# skip next element
# but i won't get affected
i += 1
end
end
# incorrect, outputs nothing... is there a next_next ?
a.each do |elt|
puts elt
if elt=="b"
# skip next element
# ??
end
end
# this one works, but is ugly
i=0
while i < a.size
puts a[i]
if a[i]=="b"
# skip next element
i += 1
end
i += 1
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
···
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
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!
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.
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.
···
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.
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?
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"
···
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?
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