こころがホッコリー

ただイカしたRubyistになりたい人生だった。

数学パズルでIQゴリラ並と判定を受けたミジンコがお世話になっているRubyの便利メソッドたち

dodosoft Advent Calendar 2016 6日目です。

www.adventar.org

dodosoftって何? という方は、こちらのエントリーをどうぞ。

okoysm.hatenablog.jp

目次

本日のお品書きはこちら。

自己紹介

Twitterではミジンコのアイコンで活動しています、@muramurasan です。
週末は dodosoft の輪読会に参加したり、デザイン思考の大学講義に出席したり、もくもくしたりしています。
普段はRuby On Railsを扱い、ECサイトのバックエンド部分を開発・保守しています。

本題

さて、本題です。 本記事では、ミジンコな私が、通称:数学パズル という本をRubyで解くのに、よくお世話になっている便利メソッドたちを紹介したいと思います。

プログラマ脳を鍛える数学パズル シンプルで高速なコードが書けるようになる70問

プログラマ脳を鍛える数学パズル シンプルで高速なコードが書けるようになる70問

ちなみにゴリラのIQは 70〜90 らしいです。意外と高いですね。

each_with_index

配列の中身をぐるぐる回しながら、インデックス(番号)を数え上げてくれます。
変数 i を定義して、インクリメントして......なんてコードを書かなくて済むので重宝します。

コード

array = ["Ruby", "On", "Rails"]
array.each_with_index { |item, i| puts "#{i}:#{item}" }

実行結果

0:Ruby
1:On
2:Rails

include?

配列の中に、指定の値が存在するかチェックしてくれるメソッドです。
配列ぐるぐる回して探索する......なんてコードを自分で書かなくてもいいわけですね。

コード

array = ["Ruby", "On", "Rails"]
puts array.include?("Rails")

実行結果

true

combination

配列から引数n個の要素を選んだときの組み合わせを数え上げてくれます。
地味に使いどころ少ないですが、組み合わせを数え上げる問題は瞬殺で解くことができます。

コード

# encoding: utf-8
array = ["生ハム", "メロン", "アイス", "キャンディー"]
array.combination(2) { |a, b| puts "#{a}#{b}" }

実行結果

生ハムメロン
生ハムアイス
生ハムキャンディー
メロンアイス
メロンキャンディー
アイスキャンディー

repeated_combination

配列から引数n個を選んだときの重複組み合わせを数え上げてくれます。
例えば、以下のような3食のメニューの組み合わせを吐かせたりすることができます。

コード

# encoding: utf-8
menu = ["和食", "洋食", "中華", "なし"]
menu.repeated_combination(3) {|a, b, c| puts "朝:#{a} 昼:#{b} 夕:#{c}" }

実行結果

朝:和食 昼:和食 夕:和食
朝:和食 昼:和食 夕:洋食
朝:和食 昼:和食 夕:中華
朝:和食 昼:和食 夕:なし
朝:和食 昼:洋食 夕:洋食
朝:和食 昼:洋食 夕:中華
朝:和食 昼:洋食 夕:なし
朝:和食 昼:中華 夕:中華
朝:和食 昼:中華 夕:なし
朝:和食 昼:なし 夕:なし
朝:洋食 昼:洋食 夕:洋食
朝:洋食 昼:洋食 夕:中華
朝:洋食 昼:洋食 夕:なし
朝:洋食 昼:中華 夕:中華
朝:洋食 昼:中華 夕:なし
朝:洋食 昼:なし 夕:なし
朝:中華 昼:中華 夕:中華
朝:中華 昼:中華 夕:なし
朝:中華 昼:なし 夕:なし
朝:なし 昼:なし 夕:なし

permutation

combinationと違い、こちらは配列から引数n個の要素を選んだときの順列を数え上げてくれます。

コード

# encoding: utf-8
array = ["", "", ""]
array.permutation(2) { |a, b| puts "#{a}#{b}" }

実行結果

あか
あお
かあ
かお
おあ
おか

発展

せっかく便利なメソッドなので、発展も紹介しておきます。
例えば、(都合の良い問題ですが)
「とある文字列から5文字選択した場合、回文はいくつ出来上がるか」 といった問題を瞬殺で解くことができます。

コード

STR = "APPLEPEN"
p STR.split("").permutation(5).map(&:join).select { |a| a == a.reverse }.uniq

実行結果

["PEAEP", "PEPEP", "PELEP", "PENEP", "EPAPE", "EPPPE", "EPLPE", "EPNPE"]

repeated_permutation なんてのもありますが、使ったことがないミジンコなので、割愛します。

product

これめちゃめちゃ使えます。
複数の配列を組み合わせて、その組み合わせを配列にして返してくれるというものです。
セットメニューを作り上げる例を見てみましょう。

コード

main  = ["ビーフ", "チキン"]
sub   = ["サラダ", "スープ"]
drink = ["コーヒー", "紅茶"]
main.product(sub, drink).each { |set| puts set.join(", ") }

実行結果

ビーフ, サラダ, コーヒー
ビーフ, サラダ, 紅茶
ビーフ, スープ, コーヒー
ビーフ, スープ, 紅茶
チキン, サラダ, コーヒー
チキン, サラダ, 紅茶
チキン, スープ, コーヒー
チキン, スープ, 紅茶

おわりに

書いてみると、半分以上がリファレンスのコピペになってしまいました。
ピックアップして紹介するのが目的の記事なので許してください......。

数学パズルは、dodosoftのメンバーと一緒に解くことがあるんですが、(みんな言語バラバラ)
Rubyは便利メソッドが多すぎるので、「卑怯だ!」と言われることがよくあります。いいんです。いーんです。
Rubyはいいぞ。」