LoginSignup
3
1

More than 3 years have passed since last update.

全ての約数を列挙する `Prime#each_divisor` を実装

Last updated at Posted at 2020-04-10

Rubyの Prime クラスには、素数を判定・列挙したり素因数分解するメソッドが実装されている。しかし素因数分解までであり、約数に関する操作は無い。約数を列挙したり、その個数を数えたりしたかったので、素因数分解のメソッドを利用して追加実装してみた。

実装
require 'prime'

class Prime
    def each_divisor(n, &block)
        pf = prime_division(n)
        num = -> { pf.inject(1) { |prod, (_, exp)| prod * exp.succ } }
        Enumerator.new(num) { |y| __each_divisor__(1, pf, &y.method(:<<)) }
                  .tap { |enum| enum.each(&block) }
    end

    private def __each_divisor__(d, ary, &block)
        return yield(d) if ary.empty?

        ary = ary.dup
        prime, exp = ary.pop
        0.upto(exp) { __each_divisor__(d, ary, &block); d *= prime }
    end
end
使用例
prime = Prime.instance

# 約数の個数
prime.each_divisor(60).size
#=> 12

# 約数でループ(ソートはされない)
prime.each_divisor(60) { |d| print d, ' ' }; print "\n"
#=> 1 2 4 3 6 12 5 10 20 15 30 60 

# Enumerableなメソッドを作用
prime.each_divisor(60).select { |d| d * d <= 60 }
#=> [1, 2, 4, 3, 6, 5]

# 1でも正しく動作
prime.each_divisor(1).to_a
#=> [1]

なお、メソッド定義はインスタンスメソッドとして実施したが、 Prime クラスの計らいでクラスメソッドとしても呼び出せる。( Prime.each_divisor(60) といった感じ)

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1