0Pricing
Scala for Backend Engineering & Functional Programming · レッスン

if によるフィルタリング

内包表記のガードです。

「if によるフィルタリング」はCoddyKit上の無料Scala for Backend Engineering & Functional Programmingレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはScala for Backend Engineering & Functional Programming学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。

for-comprehensionのガード

for-comprehensionの中には、ガードと呼ばれるif条件を追加できます。filterと同じように、条件を満たす要素だけを残します。

object Main {
  def main(args: Array[String]): Unit = {
    val evens = for (x <- 1 to 10 if x % 2 == 0) yield x
    println(evens)
  }
}

ガードはwithFilterに展開される

if condというガードは、withFilter(filterの遅延評価版)への呼び出しに書き換えられます。

  • for (x <- xs if p(x)) yield x
  • はxs.withFilter(p).map(x => x)になります
object Main {
  def main(args: Array[String]): Unit = {
    val sugar = for (x <- List(1, 2, 3, 4) if x > 2) yield x
    val desugared = List(1, 2, 3, 4).withFilter(_ > 2).map(x => x)
    println(sugar == desugared)
  }
}

filterではなくwithFilterを使う理由

withFilterは遅延評価されるため、中間コレクションを作りません。条件は後続のmapまたはflatMapが実行されたときだけ適用されるので、メモリと処理を節約できます。

object Main {
  def main(args: Array[String]): Unit = {
    val nums = List(1, 2, 3, 4, 5, 6)
    val result = for (n <- nums if n % 3 == 0) yield n * 100
    println(result)
  }
}

複数のガード

複数のガードをチェーンできます。論理ANDのように組み合わされるため、要素が残るにはすべての条件を満たす必要があります。

object Main {
  def main(args: Array[String]): Unit = {
    val result = for {
      x <- 1 to 20
      if x % 2 == 0
      if x % 3 == 0
    } yield x
    println(result)
  }
}

複数のジェネレーターに対するガード

ガードは任意のジェネレーターの後に置け、そのレベルの反復をフィルターします。テスト対象の値を生成するジェネレーターの直後にガードを置いてください。

object Main {
  def main(args: Array[String]): Unit = {
    val coprimeSums = for {
      x <- 1 to 3
      y <- 1 to 3
      if x != y
    } yield (x, y)
    println(coprimeSums)
  }
}

ガードと値のバインディングを組み合わせる

ガード(if)と値のバインディング(=)は自由に組み合わせられます。順序が重要です。ガードより前に定義したバインディングは、そのガード内で使用できます。

object Main {
  def main(args: Array[String]): Unit = {
    val result = for {
      x <- 1 to 6
      square = x * x
      if square > 10
    } yield square
    println(result)
  }
}

Stringコレクションに対するガード

ガードは数値だけでなく、任意の述語で動作します。ここでは単語を長さでフィルターしています。

object Main {
  def main(args: Array[String]): Unit = {
    val words = List("scala", "go", "java", "rust", "c")
    val longWords = for (w <- words if w.length >= 4) yield w.toUpperCase
    println(longWords)
  }
}

Optionsのフィルタリング

Optionでは、条件に合わないガードによって結果がNoneになります。これにより、for-comprehensionを使ってオプショナルな値を簡潔に検証できます。

object Main {
  def main(args: Array[String]): Unit = {
    val ok  = for (x <- Some(8) if x > 5) yield x
    val bad = for (x <- Some(3) if x > 5) yield x
    println(ok)
    println(bad)
  }
}

ガードの位置で意味が変わる

ガードからは、ガードより上で束縛された値しか参照できません。必要なジェネレーターより前に置くと、コンパイルできません。必ず、対象となるジェネレーターの後にガードを置いてください。

object Main {
  def main(args: Array[String]): Unit = {
    val result = for {
      x <- 1 to 3
      y <- 1 to 3
      if x + y == 4
    } yield s"$x + $y = ${x + y}"
    result.foreach(println)
  }
}

ガードと最後のフィルターの違い

内包表記の後で結果をフィルタリングすることもできますが、ガードは反復の途中でフィルタリングします。ジェネレーターが複数ある場合、ガードによって早い段階で分岐を取り除けるため、全体の処理量を減らせます。

object Main {
  def main(args: Array[String]): Unit = {
    val withGuard = for {
      x <- 1 to 100
      if x % 25 == 0
    } yield x
    println(withGuard)
  }
}

読みやすい検証パイプライン

ガードを積み重ねると、条件のチェックリストのように読めます。これは、実際のScalaコードでfor内包表記を使う最も慣用的な方法の一つです。

object Main {
  def main(args: Array[String]): Unit = {
    val valid = for {
      n <- List(4, 7, 12, 15, 20)
      if n > 5
      if n < 18
      if n % 2 == 0
    } yield n
    println(valid)
  }
}

クイックチェック

for内包表記のガード(if)は、どのメソッド呼び出しに糖衣構文展開されますか?

まとめ

for内包表記のガードについて学びました。

  • if condは反復中に要素をフィルタリングします
  • ガードはwithFilter(遅延フィルタリング)に糖衣構文展開されます
  • 複数のガードは論理ANDのように組み合わされます
  • ガードからは、その上で束縛された値しか参照できません
  • ガードはジェネレーターや=による束縛と自由に組み合わせられます

よくある質問

「if によるフィルタリング」レッスンは無料ですか?

はい。「if によるフィルタリング」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Scala for Backend Engineering & Functional Programmingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。

「if によるフィルタリング」で何を学びますか?

内包表記のガードです。 ブラウザで直接実行するハンズオンコードでScala for Backend Engineering & Functional Programmingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Scala for Backend Engineering & Functional Programmingを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのScala for Backend Engineering & Functional Programmingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「if によるフィルタリング」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このScala for Backend Engineering & Functional Programmingレッスンでコードを書いて実行できますか?

はい。すべてのScala for Backend Engineering & Functional Programmingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. for の脱糖
  2. if によるフィルタリング
  3. 複数のジェネレーター
  4. Option と Future の利用
← Scala for Backend Engineering & Functional Programmingに戻る