【PHP】ワンライナーでフィボナッチ数列

  • 2021年6月17日
  • PHP

フィボナッチ数列は大雑把に言えば 1 つ前の数値と 2 つ前の数値を足した結果を今の数値とする数列です。0 と 1 をスタートにして 0+1=2, 1+2=3, 2+3=5, 3+5=8,..といった具合です。漸化式で表現すると次です。

F0 = 0,
F1 = 1,
Fn+2 = Fn + Fn+1 (n ≥ 0)

フィボナッチ数 – Wikipedia

漸化式版

PHP ではこの漸化式を次の様に一行で書けます。

<?php
// 21個分のフィボナッチ数列を $v に格納するワンライナー
for([$v=[0,1],$i=1];count($v)<=21;$i++)$v[]=$v[$i-1]+$v[$i];
// ワンライナーの結果を echo
echo implode(',', $v);
// 0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946

これを読みやすくなるようにインデントとかっこをつけると次です。

for ([$v = [0, 1], $i = 1]; count($v) <= 21; $i++) {
    $v[] = $v[$i - 1] + $v[$i];
}

この中にある下記の変数の初期化はワンライナー(というよりネスト制御構文+一文)で書くための小技です。

// for ([$v = [0, 1], $i = 1]; count($v) <= 21;) { の中にあります
[$v = [0, 1], $i = 1]

PHP の変数の初期化は$i = 1;の様に式の形で行います(詳細には整数定数 1 を変数 $i に代入する代入式)。
PHP: 式 – Manual
加えて、配列の定義において配列中の各要素は式で記述されます。これにより次の様に複数の代入式を要素とした配列を定義でき、一式で任意の異なる値を持つ変数を初期化できます。
PHP: 配列 – Manual

[
  $v = [0, 1], // $v を初期化する代入式
  $i = 1,      // $i を初期化する代入式
]

一般項版

フィボナッチ数列の一般項は次です。

これを用いると制御構文すら不要の一式でフィボナッチ数列を書けます。

echo implode(',',array_map(fn($n)=>(1/sqrt(5))*(pow((1+sqrt(5))/2, $n)-pow((1-sqrt(5))/2, $n)),range(0,21)));
// 0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946
// 本体は↓
// array_map(fn($n)=>(1/sqrt(5))*(pow((1+sqrt(5))/2, $n)-pow((1-sqrt(5))/2, $n)),range(0,21))

各 n を持つ range 関数を用意して array_map 関数で一般項を適用していくのみです。
PHP: range – Manual
PHP: array_map – Manual

コードの短縮

ちなみここで紹介したフィボナッチ数列ワンライナーをコードゴルフ的に短くすると次の様に50文字にできます。

for($v=[$i=0,1];end($v)<1e4;)$v[]=$v[$i]+$v[++$i];

基本は構文整理で、増えた小技は配列末尾の値を見る end 関数と指数表記で終点を示す部分です。なかなか短くなりましたがFibonacci の様な本物のコードゴルフでは標準出力込みで40文字を切っている猛者ばかりです。

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG