こちらの記事では、たのしいRuby第6版での練習問題への取り組みの自分の間違えた記録やそれに対する考え方を記載しています。
※問題本文は書籍を直接ご参照ください。
練習問題(1)
<考え方の方針>
- 配列の初期値を[0]で作成する
- 値を1増やしてpushメソッドで配列に挿入する
- 繰り返しを利用して100まで繰り返す
- 100に達した時点でループからはじいて終了させる
- 最終の配列を出力する
<作成したコード>
def push_array(n)
a = Array.new(1, 0)
a.each do |i|
return a if i == n
while i < n
a.push(i)
i += 1
end
end
end
p push_array(100)
<結果と考察>
ループが終了せず、配列が増大し続けて、処理しきれずUbuntuが切断。
原因としては
- 繰り返しはeachを使わなければいけないと思い込んでいた
eachは各要素に対してブロック内の操作を実行するため、この場合1度目の操作で増やした要素それぞれに対してまたブロック内の操作が実行されるため、無限に配列が増え続け、ループが終了しなかった。
⇒eachを使用せず、whileのみでループを作成
<修正後のコード①>
def push_array(n)
a = [0]
i = 1
while i < n
a.push(i)
i += 1
end
return a
end
p push_array(100)
#=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
<結果と考察>
配列が99までで終了してしまった。
原因としては
- whileの条件をi < nとしてしまっていた
i = nがループに含まれず、pushされないため
⇒ i <= n に変更する
<修正後のコード②>
def push_array(n)
a = [0]
i = 1
while i <= n
a.push(i)
i += 1
end
return a
end
p push_array(100)
#=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
<結果と考察>
期待した挙動となった
脱線⇒Rubyでは戻り値が自動で設定されるらしいという耳寄り情報から、return a を削除しても結果は変わらないのではないか?と思い実行してみたところ、
nilが返されてしまった、、、
どうやらRubyでは戻り値として設定されるのは最後の行ではなく、メソッドの最後に置かれた式全体の評価結果という自分の勘違いが原因だったよう。つまりこの場合では戻り値はwhile全体となってしまうためnilが返されてしまうようだった。
練習問題(2)
<考え方の方針>
- 要素を一つずつ取り出して100倍し、元の要素と置き換える
- 100番目まで繰り返す
<作成したコード>
a2 = push_array(100)
i = 0
while i <= 100
a2[i] = i * 100
i += 1
end
p a2
#=> [0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900, 4000, 4100, 4200, 4300, 4400, 4500, 4600, 4700, 4800, 4900, 5000, 5100, 5200, 5300, 5400, 5500, 5600, 5700, 5800, 5900, 6000, 6100, 6200, 6300, 6400, 6500, 6600, 6700, 6800, 6900, 7000, 7100, 7200, 7300, 7400, 7500, 7600, 7700, 7800, 7900, 8000, 8100, 8200, 8300, 8400, 8500, 8600, 8700, 8800, 8900, 9000, 9100, 9200, 9300, 9400, 9500, 9600, 9700, 9800, 9900, 10000]
<結果と考察>
期待した挙動となった。
直前で学んだwhileの使い方を再利用できた。
※見直したところ挙動は期待通りだったが、道筋は間違っており、たまたま狙った動きになっただけだった。具体的には、この場合では元の要素を参照しておらず、インデックス番号を100倍してしまっていた。
⇒混同しないよう、空の配列を作成してa2とする。元配列の各要素を抜き出し100倍してa2へ格納する方式をとる。
<修正したコード>
a = push_array(100)
a2 = []
i = 0
while i <= 100
a2.push(a[i] * 100)
i += 1
end
p a2
#=> [0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900, 4000, 4100, 4200, 4300, 4400, 4500, 4600, 4700, 4800, 4900, 5000, 5100, 5200, 5300, 5400, 5500, 5600, 5700, 5800, 5900, 6000, 6100, 6200, 6300, 6400, 6500, 6600, 6700, 6800, 6900, 7000, 7100, 7200, 7300, 7400, 7500, 7600, 7700, 7800, 7900, 8000, 8100, 8200, 8300, 8400, 8500, 8600, 8700, 8800, 8900, 9000, 9100, 9200, 9300, 9400, 9500, 9600, 9700, 9800, 9900, 10000]
<結果と考察>
期待した挙動となった。
練習問題(3)
<考え方の方針>
- 空の配列を作成
- インデックス番号の初期値を3で設定し、該当する要素を抜き出す
- 抜き出した要素をからの配列にpushメソッドで挿入する
- インデックス番号を3増やす
- 以上の操作をwhileを用いて<= nの範囲でループを作成
<作成したコード>
a = push_array(100)
a3 = []
i = 3
while i <= 100
a3.push(a[i])
i += 3
end
p a3
#=> [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99]
<結果と考察>
期待した挙動となった。
練習問題(4)
<考え方の方針>
- 空の配列を作成
- 先頭から順番に要素を取り出す
- 取り出した要素をunshiftメソッドを使って空の配列に挿入する
<作成したコード>
作成にあたって、要素の個数を数える方法がわからず見直し⇒lengthメソッドを活用
def reverse_array(arr)
reversed = []
i = 0
while i <= arr.length
reversed.unshift(arr[i])
i += 1
end
return reversed
end
a = push_array(100)
p reversed = reverse_array(a)
#=> [nil, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
<結果と考察>
nilが一つ多く要素に含まれてしまった。
原因としては、lengthでは要素の個数を返す(自然数として1から数える)のに対して、インデックス番号は0から始まるためiの対応が1つずれてしまったため
⇒whileの範囲をi <= arr.length - 1として設定する
<修正したコード>
def reverse_array(arr)
reversed = []
i = 0
while i <= arr.length - 1
reversed.unshift(arr[i])
i += 1
end
return reversed
end
a = push_array(100)
p reversed = reverse_array(a)
#=> [100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
<結果と考察>
期待した挙動となった。
練習問題(5)
<考え方の方針>
- 要素を1つずつ取り出す
- 取り出した要素と直前の和と足し合わせる
- whileを用いてi <= arr.length-1の範囲でループを作成
<作成したコード>
a = push_array(100)
i = 0
sum = 0
while i <= a.length - 1
sum += a[i]
i += 1
end
p sum
#=> 5050
<結果と考察>
期待した挙動となった。
※作成中に1度エラーが出てしまったが、原因はsumの初期値の設定忘れと気づくことができた。改めて、「ループ」と「ループ内で更新する変数の初期値」はセットと印象付けをしておく。