visible true

技術的なメモを書く

RxJavaでフィボナッチ数列を生成しようとしたけど面白くなかった

Observableにして無限リスト的に好きなだけ生成出来る!と思ったんだけど、

Fibonacci.java

public class Fibonacci {
  public static Observable<Integer> take(int count) {
    if (count == 0) {
      return Observable.empty();
    }
    if (count == 1) {
      return Observable.just(1);
    }
    return Observable.from(new Integer[]{1, 1})
        .concatWith(Observable.zip(
            take(count - 1),
            take(count - 1).skip(1),
            (i1, i2) -> i1 + i2));
  }
}

usage

Fibonacci.take(0)
  .subscribe(i -> Log.d("Fibonacci", Integer.toString(i)));
// empty

Fibonacci.take(1)
  .subscribe(i -> Log.d("Fibonacci", Integer.toString(i)));
// 1

Fibonacci.take(2)
  .subscribe(i -> Log.d("Fibonacci", Integer.toString(i)));
// 1, 1

Fibonacci.take(10)
  .subscribe(i -> Log.d("Fibonacci", Integer.toString(i)));
// 1, 1, 2, 3, 5, 8, 13, 21, 34, 55

ところが

Fibonacci.take(15)とかで計算が爆発して死ぬ。つらい。

仕方ないので

こういう面白みのない感じに。

public class Fibonacci {
  static Map<Integer, Integer> FIBONACCI = new HashMap<>();
  static {
    FIBONACCI.put(0, 1);
    FIBONACCI.put(1, 1);
  }
  public static Observable<Integer> take(int count) {
    if (count == 0) {
      return Observable.empty();
    }
    return Observable.range(0, count)
        .map(i -> {
          if (FIBONACCI.containsKey(i)) {
            return FIBONACCI.get(i);
          }
          int result = FIBONACCI.get(i - 2) + FIBONACCI.get(i - 1);
          FIBONACCI.put(i, result);
          return result;
        });
  }
}

ただObservable化するとこういう実装も簡単にできて良い。

  public static int at(int index) {
    return take(index).last().toBlocking().single();
  }

まとめ

なんかもっといい感じの書き方ないかな