Ruby C ++ Style Irator

I would like to iterate over various ruby ​​arrays (and possibly hashes). I really don't want to maintain an index to keep track of the position in which I work for each array. This is not because I'm lazy, but I'm used to C ++ - a way to use an iterator that I think is less error prone.

So, there is a way to get an iterator in ruby, as in C ++ (this example does little, but it's just an example):

std::set< MyObject >::iterator iter1 = set1.begin(); std::set< MyObject >::iterator iter2 = set2.begin(); while(iter1 != set1.end() && iter2 != set2.end() { if (iter1->timestamp > iter2->timestamp) ++iter2; else ++iter1; } 
+4
source share
3 answers

Variable methods only iterate if you provide a block, otherwise they return an iterator that is similar to C ++. For example, in irb :

 >> e = [1,2,3,4].each => #<Enumerator: [1, 2, 3, 4]:each> >> e.next => 1 

It's hard to say that .next is a lot like e++ in C ++ because it returns the current value and increases the iterator. There is a .rewind method, but it resets the iterator to the beginning, and does not return just one step.

I don’t know about a convenient way to detect the end of an iterator (except for the StopIteration exception) or to determine how large the iterator is.

Presumably, you should grab the iterator, pass it to some method, and the method does iter.each { |x| something_interesting(x) } iter.each { |x| something_interesting(x) } .

So there are iterators, but you cannot transliterate your C ++ directly into Ruby. OTOH, you should not transliterate your C ++ to Ruby, you should write Ruby in Ruby and C ++ in C ++.

+8
source

I don’t quite understand exactly what the result of your example should be, so I can’t check if this meets your specifications, but it seems to be something you are looking for:

 iter1 = set1.each iter2 = set2.each loop do if iter1.peek.timestamp > iter2.peek.timestamp iter2.next else iter1.next end end 

Enumerator#peek roughly equivalent to dereferencing an iterator in C ++ (although it looks at the next value instead of the current one, which means there might be a fencepost error in my code). Enumerator#next advances the counter and returns the next value. The end of the enumerator is signaled by creating a StopIteration exception, which, however, is processed automatically and correctly by Kernel#loop .

+4
source

Regarding Jörg's statement:

(although it looks at the next value instead of the current one, which means there might be a fencepost error in my code).

this is trivial to check in a version of Ruby containing an enumerator view # 1.8.7 (does not appear)

 e = [10,20,30].each => #<Enumerator: [10, 20, 30]:each> e.peek => 10 

The secret is that until the first record with .next is received, the iterator is "before" the start, so .peek will show you the .next element will return.

So no fencepost error ...

What I can't find is a way to check for exhaustion by simply not relying on an exception. Would it be nice to have finished? method...

0
source

Source: https://habr.com/ru/post/1344566/


All Articles