今日のRubyドリルでの自分の脳内処理を残したくなったので、記事を書いてみることにしました。
練習問題
2つの文字列の末尾の文字を比較して、一致する場合はTrue、一致しない場合はFalseを出力するプログラムの実装。
【条件】
・メソッドの引数に、任意の2つの文字列を指定する。
・引数に指定された2つの文字列のうち、どちらかがもう一方の文字列の末尾にある場合は、Trueを出力する
・上記を満たせていない場合は、Falseを出力する
・入力された文字が大文字でも小文字でも、同一の文字として処理を行う
私の考え
①文字を大文字か小文字どちから一方に揃える
まず条件を見て、大文字でも小文字でも同一の文字として処理するために、文字を大文字か小文字どちから一方に揃える必要があると考えました。
今回が2つの文字列を全て小文字に揃えることとし、downcaseメソッドを使用しました。
downcaseメソッド
文字列に含まれる大文字を小文字に変換したいときに使用するメソッド。
使い方
文字列.downcase
例
str = "Hello World" puts str.downcase 出力結果 => hello world
ちなみにupcaseメソッドで大文字に揃える方法でもよいのかなと思いました。(使い方はdowncaseメソッドと同じ)
2つの文字列を a,bとし、小文字に変換した文字列を下記のように変数に代入しました。
a_down = a.downcase b_down = b.downcase
②どちらか一方がもう一方の文字列の末尾に含まれるかを確認する
次に、どちから一方がどちらか一方の文字列の末尾に含まれるかを確認するために、
2つの文字列の長さを比較して、長い方の末尾から短い方の文字数分文字を切り取り、
その切り取った末尾の文字列と、短い方の文字列が一致するかの判定をしたらいいのかなと思いました。
※初めはinclude?メソッドを使おうかと思ったのですが、
含まれることを確認できても、「末尾に含まれる」という部分が難しくなるのかなと思い却下。
文字数の比較
2つの文字列がそれぞれ何文字あるのか数えるためにlengthメソッドを使用しました。
lengthメソッド
配列に対して使用すると、配列の要素の数を返す。
文字列対して使用すると、文字の数を返す。
使い方
配列or文字列.length
例
array = ["red","blue","yellow"] str = "たろぽよた" array.length => 3 str.length => 5
2つの文字列を a,bとし、それぞれの文字数を下記のように変数に代入しました。
a_length = a.length b_length = b.length
2つの文字列の長さを比較して条件分離を作ってみました。
if a_length >= b_length else end
a >= b、それ以外はa<bって感じです。
a = bはどっちに含めてもいいかなと思い、1つ目の条件式に入れてみました。
文字の末尾を切り取る
文字列の末尾を切り取るために、sliceメソッドを使いました。
sliceメソッド
配列や文字列から指定した要素を取り出すことができるメソッド。
要素を指定する際は数値で指定。
⚠️先頭は0からはじまる!
使い方
配列or文字列.slice(指定したい要素の番号)
例
array = [0, 1, 2, 3, 4, 5] array.slice(1) 出力結果 =>1
sliceは範囲演算子(..)で取り出したい範囲を指定することができます。
今回の問題の場合、
a_length >= b_length の場合は、aの末尾からbの文字数分切り取りたいので、
a_down.slice(-(b_length)..-1)
それ以外(a_length < b_length)の場合は、bの末尾からaの文字数分切りたいので、
b_down.slice(-(a_length)..-1)
と、記載してみました。
長い方の文字列の末尾から切り取った文字列と、短い方の文字列が一致するかの判定をする
先ほどの条件式に、上記に書いたものをあてはめてみました。
if a_length >= b_length b_down == (a_down.slice(-(b_length)..-1)) else a_down == (b_down.slice(-(a_length)..-1)) end
完成形
def end_other(a, b) # 処理を記述 a_down = a.downcase b_down = b.downcase a_length = a.length b_length = b.length if a_length >= b_length puts b_down == (a_down.slice(-(b_length)..-1)) else puts a_down == (b_down.slice(-(a_length)..-1)) end end # 呼び出し例 end_other('POYOTA', 'poyo') end_other('TaRo', 'poYotAro') end_other("KoromAn", "KoRo") 出力結果 => false true false
想定の結果がでました。
でも細かいことを言うと、問題文は「True」「False」の表記になっているため、
指示通り忠実に。ということを考慮し、下記のように付け加えてみました。
def end_other(a, b) a_down = a.downcase b_down = b.downcase a_length = a.length b_length = b.length if a_length >= b_length result = b_down == (a_down.slice(-(b_length)..-1)) else result = a_down == (b_down.slice(-(a_length)..-1)) end if result puts "True" else puts "False" end end # 呼び出し例 end_other('POYOTA', 'poyo') end_other('TaRo', 'poYotAro') end_other("KoromAn", "KoRo") 出力結果 => False True False
大事なことは、問題文の意図をしっかり理解することだとは思うで、
判定出せたらそれでよいのかなと思いつつも...
問題をよく読む練習として実装してみました。
模範回答
def end_other(a, b) a_down = a.downcase b_down = b.downcase a_len = a_down.length b_len = b_down.length if b_down.slice(-(a_len)..- 1) == a_down || a_down.slice(-(b_len)..- 1) == b_down puts "True" else puts "False" end end
とってもシンプル!! またもや自分のコードはややこしいと思いました。
自分のコードのいいところ1個でもないかな... と考えてみました。
ちょっと強引かもしれませんが、
if文の中に||演算子を使用すると、真偽判定のために左右両方の処理をしなければいけないのに対し、
if文の中を比較演算子のみにすることで、不必要な計算がされず、処理が速くなるのかな ?と思いました。
おまけ
本日キャッチアップゼミに参加し、
他の受講者さんの貴重なご意見をたくさん聞けて、モチベーションが上がりました!
私も積極的にコミュニティを活用して、皆様のアウトプットをもっと吸収したいと思いました。