Pocket

先日、キャリアアドバイザーと初めての面談を行い、未経験からエンジニア転職するための方向性について、アドバイスをいただきました。

5月中旬から始まる就職活動までの取り組みとして、以下4点を行なっていきたいと思います。

  1. オリジナルアプリを作る
  2. 論理的思考を磨きまくる
  3. エンジニアのロードマップに従った学習
  4. WordPressとtwitterでとことんアウトプット

限られた時間で、4つもできるんかい?!と不安はありますが、まずは手を動かしてみて、自分に合う合わないを判断したいと思ってます。

今回は、”2.論理的思考を磨きまくる“について、一歩を踏み出してみたので書きたいと思います。

論理的思考力をどうやって磨くのか

キャリアアドバイザーからは、Paizaなどのサービスを利用して、プログラミングの問題を解いてみたらと指南いただきました。

TechCampでは、主にRubyとJavaScriptを学びましたが、手を動かした実践課題はほとんどやってきてなかったので、早速取り掛かりました。

Paizaのとある課題をやってみて、理解が不十分だった点について、まとめていきます。

問題:ユーザーIDを登録順に並べてください

こちらをrubyで実装してみます。

問題を要約すると、

  • はじめにユーザーIDの個数を指定する。N=5なら、5個のユーザーIDが付与される。
  • ユーザーIDは、ユーザー名(String型)+通し番号(integer型)の組み合わせで、Nの数だけランダムに生成される。
    • N=4のとき : GonNinGon24, Kamakura992, Texas46, Moomin2
  • 通し番号が若い順番に並べ替えて、出力する。
    • 出力例 : Moomin2, GonNinGon24, Texas46, Kamakura992

まずこの問題文から、次のようにコードを組み立てようと考えました。

  1. ユーザーIDを格納する配列が必要なので、二次元配列を定義しておく。
  2. ランダムに生成されたユーザーIDの通し番号(Int型)部分を抜き出す。
  3. 通し番号をN数分だけ抜き出したら、それらを降順にソートする。
  4. 結果を表示する。

上記の流れでコードを作るとして、どうやって実装すればいいか分かっていない点は、ザッとこれだけありました…

  • 二次元配列の定義のやり方
  • 文字列と数値が混ざった値から、任意の値を抜き出す方法
  • 降順、昇順のソートのやり方
  • 二次元配列2つ目の要素のソート

備忘録を兼ねて、一つずつ紹介したいと思います。

二次元配列の定義方法 : Arrayクラス

今回の問題では、文字列と数値が混ざった値から、数値だけを抜き出すプロセスが必要になります。そこで、▼のような二次元配列を定義して、”元の文字列”と”数字だけの値”を分けて格納しようと考えました。

arr[["元の文字列1", 文字列の数字部分1],["元の文字列2",文字列の数字部分2]]

すべてのユーザーIDを格納したあとで、二次元配列arrの2番目の要素に対してソートし、1番目の要素を表示すれば、要求仕様が満たせると思ったのです。

問題で与えられるパラメータで例を挙げると、、、

# 二次元配列arrを定義しておく

arr_data1 = "GonNinGon24"
arr_data2 = "Kamakura92"
arr_data3 = "Texas46"

# ▲のパラメータが与えられた場合、arr["GonNinGon24",24]のように格納したい

arr = [["GonNinGon24",24],["Kamakura92",92],["Texas46",46]]

# ▲の2番目の要素に対して、降順ソートをかけられれば、要求仕様が満たせるはず!!!

と考えたのです。

さて、二次元配列の定義方法は、配列オブジェクトのArrayクラスを使います。私はよく理解していなかったのですが、配列を定義するときに何の気なしに使っていた宣言方法は、Arrayクラスのインスタンスを生成していたのです。

# 配列の宣言方法
arr =[]
arr = Array.new

配列がクラスということは、宣言と同時に初期化もできるということで、以下で二次元配列を定義します。

# 3×2の二次元配列
arr = Array.new(3){ Array.new(2) }

#=> [[nil,nil],[nil,nil],[nil,nil]]

# 3×2の二次元配列(0で初期化)
arr = Array.new(3){ Array.new(2,0) }

#=> [[0,0],[0,0],[0,0]]

文字列と数値が混ざった値から、任意の値を抜き出す方法 : matchメソッド

繰り返しとなりますが、今回のユーザーIDは文字列数値の組み合わせです。

このユーザーIDから、欲しい値だけ取得したいときは、“matchメソッド”を使います。

# matchメソッドの使い方
オブジェクト名.match(/正規表現/)

# 使用例
str = "AppleOrangeGonNinGonMelon"

match_data = str.match(/GonNinGon/)
puts match_data[0]

#=> GonNinGon

メソッドの引数の正規表現部分に”GonNinGon”という文字列を指定したことで、文字列の中から欲しい値を取得できました。

ここで苦戦したのは、matchメソッドの戻り値です。私は”文字列に含まれている数字部分”が欲しいのに、matchメソッドの戻り値はそれとは異なりました。

要するに、matchメソッドを使って数字だけ取得するよう記載したとき、、、

str = "GonNinGon24"

match_data = str.match(/\d+/)
puts match_data

#=> #<MatchData "24">

「MatchDataは24だよ〜」と文字列で戻ってきてしまうのです。

MatchDataとはなんぞやと思って調べてみたところ、正規表現のマッチに関する情報を扱うMatchDataオブジェクト(リファレンスhttps://docs.ruby-lang.org/ja/2.1.0/class/MatchData.html)のことのようです。

簡単に言うと、matchメソッドで指定した正規表現に”マッチした文字列”や”その前後の文字列”など、matchに関するいろんな情報が格納されているオブジェクトだそうです。

つまり、私がputsしていたのは、matchした結果の情報だったということですね。MatchDataオブジェクトの値を取得したいときは、、、

str = "GonNinGon24"
match_data = str.match(/\d+/)

puts match_data[0]
# もしくは
puts $&

#=> 24

と記載すれば良いです。

降順、昇順のソートのやり方 : sortメソッド

配列やハッシュを並び替えたいときは、“sortメソッド”を使います。

戻り値は、該当の配列/ハッシュの中身を並び替えて新たに生成された配列です。

# 一次元配列のとき
arr1 = [4, 8, 12, 9]

# 1)昇順に並び替え
puts arr1.sort

#=> [4, 8, 9, 12]

# 2)降順「に並び替え
puts arr1.sort.reverse

#=> [12, 9, 8, 4]

# 二次元配列のとき
# sortメソッドは、配列内の「配列の最初の要素」を基準に並び替える
arr2 = [["Hino", 24],["Adachi", 9],["Fuchu", 5]]
puts arr2.sort

# 最初の要素 -> 文字列を基準にアルファベット順に並び替えられた
#=> [["Adachi", 9],["Fuchu", 5],["Hino", 24]]

二次元配列のときは、上記のとおり「配列の最初の要素」を基準に並び替えられました。ただ、今回やりたいのは、「配列の2番目の要素」を基準に並び替えをしたいのです。そんなときは、sortメソッドにブロック構文を用います。

二次元配列2番目の要素のソート : sortメソッドとブロック

sortメソッドでブロックを使うと、reverseメソッドを使わずに降順に並び替えられたり、今回やりたいような2番目を基準に並び替えしたりできます。

ブロックを用いて並び替えするときの定義方法は以下のような形式です。

配列(またはハッシュ).sort { |a, b| 比較方法の定義 }

# 例) 昇順に並び替える
[2,1,3].sort { |a, b| a <=> b }

#=> [1, 2, 3]

ブロック変数は、rubyを学んだときにeach文などに登場していたので馴染みがあります。ただ、”比較方法の定義”で現れた、<=>演算子は初見なので調べてみました。

<=>演算子とは??

<=>演算子は、以下のようにa,b2つのオブジェクトを比較し、1, -1, 0のいずれかを返すものです。

1 <=> 5 # 右が大きいので、-1を返す

5 <=> 1 # 左が大きいので、1を返す

1 <=> 1 # イコールなので、0を返す

Gon <=> 5 # 比較できないので、nilを返す

つまり、sortメソッドとブロックによって、

  1. 与えられた配列を頭から2つずつa, bに代入する
  2. aとbを<=>演算子で比較して、(-1, 0, 1, nil)いずれかの返り値を取得する
  3. 返り値によって、配列を並び替える

という入れ替え作業をやってくれてるんですね。

ちなみに、a <=> b だと昇順、b <=> a だと降順でソートされます。

二次元配列の2番目の要素を比較する

ブロックを理解したところで本題です。

二次元配列をソートするために、以下のように書くと、配列1番目の文字列が基準となり、狙い通りの結果にはなりませんでした。

arr2 = [["Hino", 24],["Adachi", 9],["Fuchu", 5]]
arr2.sort { |a, b| a <=> b }

#=> [["Adachi", 9],["Fuchu", 5],["Hino", 24]]

2番目からソートするには、比較方法の定義部分のブロックをa[1] <=> b[1]と書き、配列の2番目を見るよう指示してあげます。

arr2 = [["Hino", 24],["Adachi", 9],["Fuchu", 5]]
arr2.sort { |a, b| a[1] <=> b[1] }

#=> [["Fuchu", 5],["Adachi", 9],["Hino", 24]]

こうすることで、arr2の配列それぞれの2番目の要素(数字部分)を基準に、昇順で並べ替えができました。

まとめ

問題を1つ解いただけで、これだけのボリュームの知らないことが出てきました。

これを何度も何度も繰り返すことで、言語を身につけていくんだと思いながら、続けていきたいと思います。

参考

投稿者

waco@jp

30代未経験でエンジニア転職を目指しています。前職はメーカーで営業と製品開発を担当。22年3月からTechCampを受講し、5月に卒業。現在、就活とオリジナルアプリケーション制作の両輪で活動しています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です