はじめに
こんにちは!アメリカで独学でソフトウェアエンジニアを目指しているものです。
今回はフィボナッチ数列を計算するプログラムを題材に、コードの改善方法や学んだことを共有します。
問題の内容
整数 n
を受け取り、フィボナッチ数列の最初の n
個を表示してください。
フィボナッチ数列は以下のように定義されます:
- F(0) = 0
- F(1) = 1
- F(n) = F(n-1) + F(n-2) (n >= 2)
例えば、n = 10
の場合は以下を出力します
0
1
1
2
3
5
8
13
21
34
私の解答
def generate_pattern(n)
f_b = 0
f = 1
f_a = 0
(1..n).each do |i|
case i
when 1
puts f_b
when 2
puts f
else
f_a = f + f_b
puts f_a
f_b = f
f = f_a
end
end
end
generate_pattern(10)
このコードでも正しくフィボナッチ数列を出力できますが、case
文を用いて i
の値を判定しているため、やや冗長に感じます。
i == 1
の場合は0、i == 2
の場合は1、それ以降はフィボナッチ数列を計算しています。
上記のコードの改善
case
文を使わず、最初の2つの値を条件分岐で単純に出力し、その後 3..n
のループで残りの値を生成する方法に改善します。
def generate_pattern(n)
f_b = 0
f = 1
# nが1以上なら、最初の値0を表示
puts f_b if n >= 1
# nが2以上なら、次の値1を表示
puts f if n >= 2
# 3番目以降の値は繰り返しで計算
(3..n).each do
f_a = f + f_b
puts f_a
f_b = f
f = f_a
end
end
generate_pattern(10)
もしn
が3より小さいと範囲が空(3以上の数が存在しない)となり、ループは一度も実行されません。
さらにシンプルな解法
この解き方もChatgptを使用して出力してもらいました。
この例では配列を使っています
def generate_fibonacci(n)
# 初期値を設定
fib = [0, 1]
# nが2より大きい場合は、3番目以降の要素を追加
(2...n).each do
fib << fib[-1] + fib[-2]
end
# 最初のn個を表示
fib.first(n).each { |num| puts num }
end
generate_fibonacci(10)
このコードでは、fib
配列の末尾から2つの要素を足して次の要素を生成していくため、計算ロジックが明確で、if
や条件分岐がほとんど必要ありません。
(2...n)
という範囲を用いることで、最初の2つの値(0と1)はすでに決まっているため、ループは3番目の値から計算を始めます。
fib.each { |num| puts num }
ではなく、fib.first(n).each { |num| puts num }
であるのは、n
が 1 の場合でも 0 と 1 の2つの要素を出力してしまい、要件である「最初の n 個」を正しく満たしていません。
なぜ配列を使うと簡潔なのか
- 最初の2つの値を [0,1] として確定しておくことで、
if
文を使わずにすべてをループで処理できます。 -
fib[-1]
やfib[-2]
など、配列末尾の要素を簡単に参照できるため、計算がシンプルです。
学んだこと
- 重複や冗長な条件分岐を避ける
最初の2つの値だけ特別扱いするためにif
やcase
文を多用すると、コードが読みづらくなります。
最初から [0, 1] を配列に設定し、後続の値をループで計算する方法の方が直感的でスッキリ書けます。
まとめ
最初のコードは機能は正しかったものの、case 文で条件分岐するなど、やや冗長でした。
初見で思い浮かぶほどの演習はできていないのでこれからもアウトプットと復習を継続してコーディング力をあげていきたいです