6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Scala] 無限ループ内で break を使わない方法を考える

Last updated at Posted at 2015-01-10

ポエムではないです。が思考の経過を垂れ流してます。

scala では break 制御構文が使えませんが、無限ループ内で、値を生成してその値をループの外で使いたいなんてことがたまにあります。
今回はシーケンスの中から使われていないユニークな値を探してそれを使うケースで考えます。
ちなみに、ライブラリで提供されている break を利用することはできますが、例外を発生させてそれをキャッチして処理するというのは個人的に好きじゃないので別の方法を考えます。(好みです(^^;)

まず単純に考えると、ループの継続を行うかどうかを変数に入れて制御する以下の方法があるかと思います。

var loop: Boolean = true
var candidate: Int = 0
while(loop) {
  candidate = Random.nextInt()
  if (seq.indexOf(candidate) == -1)
    loop = false
}

この場合、loop, candidate がミュータブルになっているのでなんとなくバグが入り込みそうで嫌な感じです。
この var を取り除くために無限ループ部分を関数にして値が見つかり次第 return してしまう方法が思いつきます。

def scanUniqValue(seq: Seq[Int]): Int = {
  while(true) {
    val candidate = Random.nextInt()
    if (seq.indexOf(candidate) == -1)
      return candidate
  }
  sys.error("never reach")
}

val x = scanUniqValue(seq)

この場合、最後に型を合わせるために、関数の最後にダミーの値を返すか例外を発生させないと型が合わずコンパイルができません。
これもまたなんか気持ち悪いです。。。

次に・・・再帰はパスします・・・w

scala なんだしもうちょっとなんかあるんでないのかと思って試行錯誤した結果、最終的に行き着いた方法がこれ。

Iterator.continually(Random.nextInt()).find(seq.indexOf(_) == -1).get

Iterator.continually で無限に値を生成しつつ、find で一番最初に見つかった値を取得しています。
値の生成部分と検索の部分が明確に分かれてて理解しやすいし個人的にはこれが一番スッキリかなぁ。

他に良い書き方があればコメントください。

以上です。

6
5
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?