2013-05-02 52 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