Bye Bye Moore

PoCソルジャーな零細事業主が作業メモを残すブログ

ブロックやラムダを使った再帰表現のお勉強

ブロックやラムダ式を使った再帰表現のお勉強をしてみました。
なお、以下の例はどれもinjectでやった方が早い例です。

Hashie::Extensions#deep_find_allの場合

module Hashie
  module Extensions
    module DeepFind

      def deep_find_all(key)
        matches = _deep_find_all(key)
        matches.empty? ? nil : matches
      end
#...
      private
#...

      def _deep_find_all(key, object = self, matches = [])
        if object.respond_to?(:key?)
          matches << object[key] if object.key?(key)
          object.values.each { |v| _deep_find_all(key, v, matches) }
        elsif object.is_a?(Enumerable)
          object.each { |v| _deep_find_all(key, v, matches) }
        end

        matches
      end
    end
  end
end

この方式に則ると、injectでもかけそうな文字列連結は次のように書き下せます。

def test (ary, sum = "")
  (ary.is_a?(Enumerable)) ? ary.each{|i| test(i,sum)} : sum.concat(ary[0])  
  sum
end

ラムダ式の場合

ラムダ式でも当然のように再帰を使う事が可能です。

factorial = lambda do |n|
  n <= 1 ? 1 : (n * factorial.call(n - 1))
end

これを呼び出すと…

factorial.call(3)
#=> 6

factorial.call(5)
#=> 120

この場合、先程の例は

test = lambda{|i,j| (i.is_a?(Enumerable)) ? i.each{|x| test.call(x,j)} : j.concat(i[0]); j}

test.call(%w(a b c),"")
#=> "abc"

となります。