いろんな再帰でFizzBuzzを試してみた

再帰で書く場合まず以下を思い浮かべるので、ちょっと書き方が変わります。

  • n-1 まではよろしくやってもらって n の時を頑張る
  • 一つを自分がやって、残りを丸投げ
再帰でFizzBuzz - 2008-03-20 - 自作のソフト開発記録

なるほど。
これまではこっちしか考えていなかった。

  • 一つを自分がやって、残りを丸投げ

こんな方法もあるのか。というか普通にあるよね。僕がなにも考えていなかっただけ。

  • n-1 まではよろしくやってもらって n の時を頑張る

というわけで「n-1 まではよろしくやってもらって n の時を頑張る」バージョンをやってみた。

public class FizzBuzzRecursion2{
  public static void main(String args[]){
    rec(100);
  }
  
  // n-1 まではよろしくやってもらって n の時を頑張るバージョン
  public static void rec(int i){
    if(i > 1) rec(i-1);

    if(i%15 == 0){
      System.out.println("FizzBuzz");
    }else if(i%5 == 0){
      System.out.println("Buzz");
    }else if(i%3 == 0){
      System.out.println("Fizz");
    }else{
      System.out.println(i);
    }
  }
}

こないだ書いた「1つ自分がやって、残りを丸投げバージョン」はこれ。

public class FizzBuzzRecursion{
  public static void main(String args[]){
    rec(1,100);
  }
  
  public static void rec(int i, int max){
    if(i%15 == 0){
      System.out.println("FizzBuzz");
    }else if(i%5 == 0){
      System.out.println("Buzz");
    }else if(i%3 == 0){
      System.out.println("Fizz");
    }else{
      System.out.println(i);
    }
    if(i < max){
      rec(i+1,max);
    }
  }
}

後者の方法はリンク先の方法と同じ考え方なのかもしれませんが、再帰呼び出し時に残り部分が減っている感がないところに若干違和感を感じます。実際は(k, n)で呼ばれた時に自分でkを処理して(k+1, n)を丸投げしているので残り部分が減っているというのは同じなのですけど、+1というのがどうも。

再帰でFizzBuzz - 2008-03-20 - 自作のソフト開発記録

僕も+1はなんだかなぁと思った。
そしてなぜ最初に「1つ自分がやって、残りを丸投げバージョン」を、こんな風に書いたのか考えてみる。

  • for文をそのまま置き換えていた(気分はfor(int i=1; i<=100; i++)だった)
  • (1..100)がJavaではできない
  • 普通の配列で簡単にひとつとって残りを渡すことができない

1〜100の処理だと、大抵for文で書くので問題ないが、せっかく再帰を使っているのにfor文使うのもなんだかね。
java.util.ListでIterator使えばhasNexstとかがあるけど、これもなんだかね。

というわけで、Javaの「1つ自分がやって、残りを丸投げバージョン」で i+1 を使わないよい方法が思いつかない。


あと間違えて気付いたこと。
if(i > 0) rec(i-1); こうやると0の時も実行されてしまう。
if(i == 0) return;でもできるけど、voidメソッドで return; ってやるのがあまり好きではない。
まあ好き嫌いの問題かな。

こないだも書いたけど、FizzBuzzはすごいなぁ。
こんなにいろんなことが学べる。