tawara's blog

雑記。個人の見解です。

Rubyで最頻値を求める2つの方法

こんにちは、たわらです。

業務駆け出して歴一年になるのですが、Ruby力のなさに直面しました。 そこで競プロをかじりはじめました。

RUNTEQというプログラミングスクールの後輩?のオオハシさんにアルゴ式なるアルゴリズムを鍛えられる学習サイトを教えてもらったのでしゅくしゅくと学習しています。

ということで、最頻値を求める問題にぶつかり、いろいろ調べたのでまとめます。

algo-method.com

問題

二行目の数字の最頻値を調べよ。答えは9ですね。

10
1 5 2 9 6 4 9 3 4 9

解法1 group_byしてmax_byするやり方

n, *a = $<.read.split.map &:to_i
puts a.group_by(&:itself).max_by{|_,v| v.size}.first

プロセスはこんな感じ。

  1. group_byで要素自身の数をkeyに、対応する要素の配列をvalueにしたhashを作成。
  2. max_byを利用して、valueの数が最大の要素(=最頻値)を含む配列を取得。
  3. 答えに必要な最頻値を取得する
p a.group_by(&:itself)
# => {1=>[1], 5=>[5], 2=>[2], 9=>[9, 9, 9], 6=>[6], 4=>[4, 4], 3=>[3]}

p a.group_by(&:itself).max_by{|_,v| v.size}
# => [9, [9, 9, 9]]

p a.group_by(&:itself).max_by{|_,v| v.size}.first
# => 9

解法2 tallyを使ってsort_byするやり方

n,*a = $<.read.split.map(&:to_i)
p a.tally.sort_by(&:last).last[0]

プロセスはこんな感じ。

  1. tallyを使用して、配列のそれぞれの要素をkeyに、要素の出現回数をvalueにしたhashに整形する。
  2. sort_byを利用して、valueを昇順に並べ替えた配列を取得。
  3. 最後の要素を取得。(出現回数が最も多い数字と出現回数のペアの配列)
  4. 出現回数が最も多い数字を配列から取り出す
p a.tally
# => {1=>1, 5=>1, 2=>1, 9=>3, 6=>1, 4=>2, 3=>1}

p a.tally.sort_by(&:last)
# =>[[1, 1], [5, 1], [2, 1], [6, 1], [3, 1], [4, 2], [9, 3]]

p a.tally.sort_by(&:last).last
# =>[9, 3]

p a.tally.sort_by(&:last).last[0]
# =>9

いろいろやり方あるんですねー。たくさん問題解いて、手になじませたいです。

参考文献

Enumerable#group_by (Ruby 3.0.0 リファレンスマニュアル)

Enumerable#max_by (Ruby 3.0.0 リファレンスマニュアル)

Enumerable#tally (Ruby 3.0.0 リファレンスマニュアル)

Enumerable#sort_by (Ruby 3.0.0 リファレンスマニュアル)