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

November 03, 2021

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

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

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

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

アルゴ式

問題

二行目の数字の最頻値を調べよ。答えは 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.1 リファレンスマニュアル)

https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/max_by.html

https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/tally.html

https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/sort_by.html