2013-05-02 37 views
2

我看到有在Ruby中一個相對較新的功能,它允許鏈式迭代 - 換句話說,而不是each_with_indices { |x,i,j| ... }你可能會做each.with_indices { |x,i,j| ... },其中#each返回Enumerator對象,Enumerator#with_indices導致額外的產量參數被包括在內。在Ruby的C擴展實現鏈接的迭代器

因此,Enumerator有其自己的方法#with_index,大概是一維對象,source found here。但我無法弄清楚將其適用於其他對象的最佳方法。

要清晰,響應評論: Ruby沒有一個#each_with_indices現在 - 這只是有一個#each_with_index。 (這就是爲什麼我要創建一個)

一連串的問題,自己的鏈接:

  1. 一個怎樣適應鏈式迭代到一個維對象?只需做一個include Enumerable
  2. 推測上述(#1)不適用於n三維對象。會創建一個EnumerableN類,從Enumerable派生,但#with_index轉換爲#with_indices
  3. 可以使用C編寫的Ruby擴展完成#2嗎?例如,我有一個矩陣類,它存儲各種類型的數據(浮點數,雙精度數,整數,有時是常規的Ruby對象,)。枚舉需要首先根據下面的示例檢查數據類型(dtype)。

例子:

VALUE nm_dense_each(VALUE nm) { 
    volatile VALUE nm = nmatrix; // Not sure this actually does anything. 
    DENSE_STORAGE* s = NM_STORAGE_DENSE(nm); // get the storage pointer 

    RETURN_ENUMERATOR(nm, 0, 0); 

    if (NM_DTYPE(nm) == nm::RUBYOBJ) { // matrix stores VALUEs 

    // matrix of Ruby objects -- yield those objects directly 
    for (size_t i = 0; i < nm_storage_count_max_elements(s); ++i) 
     rb_yield(reinterpret_cast<VALUE*>(s->elements)[i]); 

    } else { // matrix stores non-Ruby data (int, float, etc) 

    // We're going to copy the matrix element into a Ruby VALUE and then operate on it. This way user can't accidentally 
    // modify it and cause a seg fault. 
    for (size_t i = 0; i < nm_storage_count_max_elements(s); ++i) { 
     // rubyobj_from_cval() converts any type of data into a VALUE using macros such as INT2FIX() 
     VALUE v = rubyobj_from_cval((char*)(s->elements) + i*DTYPE_SIZES[NM_DTYPE(nm)], NM_DTYPE(nm)).rval; 
     rb_yield(v); // yield to the copy we made 
    } 
    } 
} 

所以,我的三個問題合而爲一:我怎麼會寫,在C,一個#with_indices到鏈到上述NMatrix#each方法?

我並不特別想讓任何人覺得我要求他們爲我編碼,但如果您確實想要,我們很樂意讓您參與我們的項目。 =)

但是如果你知道網絡上其他地方的一些例子如何完成這個例子,那麼這將是完美的 - 或者如果你可以用文字解釋,那也是可愛的。

+0

不,沒有這樣的功能。 Ruby 1.9中沒有提及任何內容。 Ruby 2.0中沒有提到你提到的這種東西。然而,Ruby有一個不同的東西叫'each_with_index'。 Ruby 1.9引入了'with_index'。 – sawa 2013-05-02 06:29:38

+0

好的,解決了我的問題 - 現在已經是Ruby的一般了。你有沒有下降?我可以問爲什麼?這是一個非常仔細的書面問題。 – 2013-05-02 15:19:29

+0

@sawa:他不問Ruby的功能。這是一個高層次的問題,他是一個開發人員,可能是NMatrix團隊的一員,他基本上要求在C中編寫Ruby方法的Ruby方式是什麼:-)我是(目前)Marc-Andre的Matrix用戶,以及我很高興有NMatrix作爲替代方案。 – 2013-05-02 15:34:19

回答

1

#with_indexEnumerator方法:http://ruby-doc.org/core-1.9.3/Enumerator.html#method-i-with_index

我想你可以做的Enumerator一個子類,具有#with_indices,有你的#each返回類的實例?這是首先想到的,雖然你的統計員可能必須非常耦合到原始類...

+0

是的,但我認爲他的問題是他想用C編寫它。他與我們的乳蛋餅食客完全不同;-) – 2013-05-02 17:09:22

+0

當然,但首先理解Ruby中的原則是很好的。我認爲問題是'Enumerator' /'Enumerable'沒有'#with_indices',只有'#with_index'。我不確定創建前者的適當機制。 – 2013-05-02 17:11:02

+0

大多數(所有?)'Enumerable'方法都會返回一個'Enumerator',如果你沒有傳入一個塊。這就是'foo.map.with_index','bar.each.with_object'等的工作方式。 – kejadlen 2013-05-02 17:26:35

0

既然你說你也對Ruby語言學感興趣,不只是C,讓我貢獻我的5美分,沒有聲稱真正回答這個問題。 #each_with_index#with_index已經變得非常地道,大多數人依賴索引是一個數字。因此,如果你以這種方式去實施你的NMatrix#each_with_index,那麼在{ |e, i| ... }的塊中它會提供例如。陣列[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], ...作爲索引i,你會驚訝的人。另外,如果其他人將您的NMatrix#each統計員與#with_index方法聯繫起來,他們將只收到一個索引號碼。因此,事實上,你是正確的結論,你需要一個不同的方法來照顧了2只指數型(或者更一般地說,正指數高維矩陣):

matrix.each_with_indices { |e, indices| ... } 

這個方法應該返回2維(n維)數組爲indices == [i, j]。你不應該去的版本:

matrix.each_with_indices { |e, i, j| ... } 

對於#with_index方法,這是不是你關心的。如果您的NMatrix提供#each方法(它當然會),那麼#with_index將正常工作,不受您的控制。而且您不需要考慮引入矩陣特定的#with_indices,因爲#each本身並不是特定於矩陣,而是對於任何類型的一維有序集合。最後,對於不熟練的C程序員來迎合您的C相關部分的問題感到抱歉。

+0

真的嗎?一個數組而不是一個*數組?你能提供一些理由嗎?這是一個有趣的想法,但我不確定我是否確信。 – 2013-05-02 17:35:41

+0

理由是,其他人會拿出更高維的物體。比如三維矩陣(我不應該稱之爲張量)。無論維數如何,您都可以預期行爲。在Ruby中,編寫'i,j = indices'非常簡單。我懷疑,用戶甚至不需要編寫'i,j = indices',而是通過讓i,j預先打包並且不需要寫'curr_pos = [i,j]'這樣的東西來方便... – 2013-05-02 17:40:30

+0

當前代碼佔據更高的維度。你只要做'#each_with_indices {| val,i,j,k,l |例如。 – 2013-05-02 18:09:55