2014-01-15 2 views
2

Предположим, я хочу получить первое число внутри массива, которое появляется в нем только один раз.Обратитесь к объекту вызывающего объекта внутри блока перечислимого метода

Таким образом, как правило, я хотел бы сделать это следующим образом:

arr = [1,1,2,2,3,4,4] 
arr.detect { |elem| arr.count(elem) == 1 } # => 3 

Я задавался вопросом, возможно ли, чтобы получить массив без необходимости предварительно присвоить его переменной, как-то вроде этого:

[1,1,2,2,3,4,4].detect { |elem| self.count(elem) == 1 } # => NoMethodError 

Это, конечно же, не работает, потому что self в приведенном выше обращении ссылается на Object.

Итак, возможно ли каким-либо образом обратиться к объекту, по которому в его блоке был вызван перечислимый метод, как в примере выше?

+2

Я хотел бы сделать это таким образом: 'arr.group_by (&: to_i) .detect {| _, л | l.size == 1} [0] '. – Hauleth

ответ

0

Я хотел бы использовать BasicObject#instance_eval:

Оценивает строку, содержащую Ruby, исходный код, или данный блок, в пределах контекст приемника (obj). Чтобы установить контекст, переменная self устанавливается в obj во время выполнения кода, предоставляя коду доступ к переменным экземпляра obj. В версии экземпляра instance_eval, который принимает строку, необязательные второй и третий параметры предоставляют имя файла и номер начальной строки, которые используются при представлении ошибок компиляции.

ary = [1,1,2,2,3,4,4] 
ary.instance_eval do 
    detect { |elem| count(elem) == 1 } # => 3 
end 
+1

Спасибо, только что я хотел :) Теперь я могу использовать его в довольно однострочных, например '[1,1,2,2,3,4,4] .instance_eval {detect {| elem | count (elem) == 1}} ' – Jacka

2

Ха, это было интересное упражнение, спасибо, что:

module Enumerable 
    def with_self 
    return to_enum(:with_self) unless block_given? 
    each do |element| 
     yield element, self.entries 
    end 
    end 
end 

[1,1,2,2,3,4,4].detect.with_self { |elem, zelf| zelf.count(elem) == 1 }