2011-03-21 79 views
4

我想遍歷不同的ruby數組(可能是散列)。我並不想維護一個索引來跟蹤每個陣列的位置。這不是因爲我很懶,而是習慣了使用迭代器的C++方式,我認爲這不太容易出錯。Ruby C++樣式迭代器

那麼,有沒有辦法++來獲得紅寶石迭代器,就像我們在C做(這個例子沒有做太多,但它只是一個例子的緣故):

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; 
} 
+0

這就像你有一個三明治,但你寧願吃一個簡單的麪包。 – texasbruce 2012-11-05 05:02:52

回答

8

可枚舉的方法只有在提供塊時纔會迭代,否則返回類似於C++的an iterator。例如,在irb

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

的棘手的事情是.next是很像e++在C++中,它返回當前值和增量迭代器。有一個.rewind方法,但重置迭代器的開始,而不是隻返回一步。

我不知道一個方便的方法來檢測迭代器的結束(除了捕獲StopIteration異常)或確定迭代器有多大。

大概,你應該抓住迭代器,將它傳遞給某種方法,並且該方法執行某種iter.each { |x| something_interesting(x) }

所以,有迭代器,但你不能真正音譯你的C++直接到Ruby。 OTOH,你不應該把你的C++音譯成Ruby,你應該用C++編寫Ruby和C++。

+0

+1,特別是最後一部分。不幸的是,Ruby,Python,Java等中的迭代器極大地簡化了迭代器接口,但代價是隻能自然地輕鬆處理* one *列表。另一方面,它們確實爲一次處理多個列表提供了一些支持(例如,Python的'map'和'zip')。 – 2011-03-21 11:19:06

+0

謝謝,雖然我們無法檢查循環的最後一個元素,但這是一種遺憾。關於最後的註釋,你將如何通過ruby中的不同數組進行迭代?此外,是否有相同類型的散列迭代器? – Arthur 2011-03-21 12:15:39

+0

@jules:迭代器由Enumerable提供,因此它可以與任何Enumerable(包括Hash)一起使用。請參閱Jörg的'.peek'方法來近似音譯C++;我可能想要從頂層開始備份並啓動一個Ruby解決方案,而不是逐個替換C++方法。 – 2011-03-21 19:38:59

4

這不是很清楚,我什麼究竟你的例子的結果應該是,所以我不能對此進行測試是否符合您的要求,但它似乎是大約你在找什麼:

iter1 = set1.each 
iter2 = set2.each 

loop do 
    if iter1.peek.timestamp > iter2.peek.timestamp 
    iter2.next 
    else 
    iter1.next 
    end 
end 

Enumerator#peek大致等價於C提領該迭代++(雖然它偷窺在值代替當前一個,這意味着有可能在我的代碼柵欄柱錯誤)。 Enumerator#next推進枚舉器並返回下一個值。通過舉例說明StopIteration例外情況來通知枚舉器的結束,但是該例外通過Kernel#loop自動正確處理。

0

關於約爾格聲明:

(雖然它在偷窺的下一個值,而不是當前的,這 意味着有可能是我的代碼柵欄柱的錯誤)。

是微不足道含枚舉#偷看Ruby的版本測試(1.8.7不會出現)

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

祕密,直到你取得與。接下來的第一項中,迭代器在開始之前是「之前」的,所以.peek會向你顯示item .next會返回。

因此,沒有fencepost錯誤...

我無法找到的是一種測試耗盡的方法,無需依賴拋出的異常。有一個完成的將是很好的?方法...