2013-05-02 2 views
2

Я вижу, что есть относительно новая функция в Ruby, который позволяет цепочечные итерации - другие слова, вместо того, чтобы each_with_indices { |x,i,j| ... } вы могли бы сделать each.with_indices { |x,i,j| ... }, где #each возвращает Enumerator объект и Enumerator#with_indices вызывает дополнительные параметры урожайности, которые должны быть включены.Реализации сцепленных итераторов в расширении рубина C

Таким образом, Enumerator имеет свой собственный метод #with_index, предположительно для одномерных объектов, source found here. Но я не могу найти лучший способ адаптировать это к другим объектам.

Чтобы был ясен, и в ответ на комментарий: Рубин не имеет #each_with_indices прямо сейчас - это только получило #each_with_index. (. Вот почему я хочу создать)

ряд вопросов, которые сами прикованы:

  1. Как бы один адаптировать цепочечную итерации к один-мерного объекта? Просто сделайте include Enumerable?
  2. Предположительно вышеприведенное (№ 1) не будет работать для n -мерный объект. Будет ли создан класс EnumerableN, полученный от Enumerable, но с #with_index преобразован в #with_indices?
  3. Может ли # 2 быть сделано для расширений Ruby, написанных на C? Например, у меня есть класс матрицы, в котором хранятся различные типы данных (поплавки, двойники, целые числа, иногда обычные объекты 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

+0

Хорошо, исправил мой вопрос - теперь он общий для Руби. Вы спустили вниз? Могу я спросить, почему? Это довольно тщательно написанный вопрос. –

+0

@sawa: Он не спрашивает о функциях Ruby. Это вопрос высокого уровня, он является разработчиком, вероятно, частью команды NMatrix, и он в основном спрашивает, что такое Ruby-метод написания Ruby-методов в C :-) Я (сейчас) пользователь Matc-Andre's Matrix и Я рад, что NMATrix arround в качестве альтернативы. –

ответ

1

#with_index является метод Enumerator: http://ruby-doc.org/core-1.9.3/Enumerator.html#method-i-with_index

Я полагаю, вы могли бы сделать подкласс Enumerator, который имеет #with_indices и есть ваш #each вернуть экземпляр этого класса? Это первое, что приходит на ум, хотя ваш перечислитель, возможно, должен быть очень привязан к первозданному классу ...

+0

Да, но я думаю, что его проблема в том, что он хочет написать его в C. Он находится на совершенно другом уровне, чем мы, продавцы quiche ;-) –

+0

Конечно, но сначала хорошо понять принципы в Ruby. Я думаю, проблема заключается в том, что 'Enumerator' /' Enumerable' не имеет '# with_indices', а только' # with_index'. Я не уверен в соответствующем механизме создания первого. –

+0

Большинство методов (всего?) 'Enumerable' возвращают' Enumerator', если вы не передадите им блок. Вот как работают 'foo.map.with_index',' bar.each.with_object' и т. Д. – kejadlen

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

Действительно? Массив вместо массива *? Можете ли вы дать какое-то обоснование этому? Это интересная мысль, но я не уверен, что еще не убежден. –

+0

Обоснование в том, что другие придумают высокомерные объекты. Такие, как 3-мерные матрицы (которые я не должен называть тензорами). И там у вас есть ожидаемое поведение, независимо от количества измерений. И в Ruby очень легко написать 'i, j = index'. Я подозреваю, что пользователям часто даже не нужно писать 'i, j = индексы', и вместо этого они будут укомплектованы тем, что i, j prepackaged и не нужно писать что-то вроде' curr_pos = [i, j] '... –

+0

Текущий код учитывает более высокие размеры. Вы просто выполняете '#each_with_indices {| val, i, j, k, l | ...} 'например. –

Смежные вопросы