Forum: Ruby Cycle enumerator

E088bb5c80fd3c4fd02c2020cdacbaf0?d=identicon&s=25 Jesús Gabriel y Galán (Guest)
on 2014-06-26 18:22
(Received via mailing list)
Hi,

I was surprised today with a behaviour, maybe my expectation was wrong
and someone can explain why it works this way:

I have an array of elements, and I want to cycle through it assigning
each element to another list of elements. But the cycle can be already
in the middle. For example:

a = [1,2,3]

b = [6,7,8,9,10]

the desired result should be (if the next element in the cycle was 2):

[[6,2], [7,3], [8,1],[9,2],[10,3]]

So I, intuitively tried this:

2.0.0-p195 :469 > b = [6,7,8,9,10]
 => [6, 7, 8, 9, 10]
2.0.0-p195 :471 > a = [1,2,3].cycle
 => #<Enumerator: [1, 2, 3]:cycle>
2.0.0-p195 :472 > a.next
 => 1
2.0.0-p195 :473 > a.peek
 => 2
2.0.0-p195 :474 > b.zip(a)
 => [[6, 1], [7, 2], [8, 3], [9, 1], [10, 2]]

So, it seems that the enumerator a is starting from the beginning,
instead of from the "next". If I read correctly the source code (MRI)
it seems that zip uses take, and testing this shows that it always
starts from the beginning:

2.0.0-p195 :475 > a.take 2
 => [1, 2]
2.0.0-p195 :476 > a.take 2
 => [1, 2]
2.0.0-p195 :477 > a.take 2
 => [1, 2]

Is it wrong to expect the enumerator to behave as a cycle starting
from its current position for operations like zip and take?

Jesus.
Adf7d4a2a49161a48ca1863a49f8af37?d=identicon&s=25 Carlos Agarie (Guest)
on 2014-06-26 18:34
(Received via mailing list)
This is surprising behavior to me. In case no one finds a good
explanation
in this mailing list, I think you should send a ticket to ruby-core
asking
why it works this way (and fixing it in case there isn't a good reason
to).


-----
Carlos Agarie
Software Engineer
+55 11 97320-3878 | @carlos_agarie


2014-06-26 13:21 GMT-03:00 Jesús Gabriel y Galán
<jgabrielygalan@gmail.com>:
8e0cd4c15482707c918697b8bab14c3f?d=identicon&s=25 Juanjo Conti (Guest)
on 2014-06-26 19:02
(Received via mailing list)
This is not an answer for your question. But you can solve your original
problem like this:

> a = [1,2,3].rotate(1).cycle
=> #<Enumerator: ...>
> b = [6,7,8,9,10]
=> [6, 7, 8, 9, 10]
> b.zip(a)
=> [[6, 2], [7, 3], [8, 1], [9, 2], [10, 3]]

Greets!

2014-06-26 13:21 GMT-03:00 Jesús Gabriel y Galán
<jgabrielygalan@gmail.com>:
E088bb5c80fd3c4fd02c2020cdacbaf0?d=identicon&s=25 Jesús Gabriel y Galán (Guest)
on 2014-06-27 22:56
(Received via mailing list)
On Thu, Jun 26, 2014 at 6:34 PM, Carlos Agarie <carlos.agarie@gmail.com>
wrote:
> This is surprising behavior to me. In case no one finds a good explanation
> in this mailing list, I think you should send a ticket to ruby-core asking
> why it works this way (and fixing it in case there isn't a good reason to).

For the record: I asked in ruby-core and the answer is that it is a
design decision:

Marc-Andre Lafortune said:

"Your confusion is understandable, but this is not how the enumerators
were designed. At the end of the doc for `next` you'll find:

    Note that enumeration sequence by next does not affect other
non-external enumeration methods, unless the underlying iteration
methods itself has side-effect, e.g. IO#each_line

I think this design choice is in part because using `next` is much
slower then `each`."

So I guess that's it.

Jesus.
5c4e55b92169c16ce2ca8fd75318eded?d=identicon&s=25 David Unric (dunric)
on 2014-06-27 22:58
From the Enumerator#next documentation:

"Note that enumeration sequence by next does not affect other
non-external
enumeration methods, unless the underlying iteration methods itself has
side-effect, e.g. IO#each_line."

So methods not working with internal position pointer are not affected
with #next .
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.