【Scala】Scala ~ 基本編 / 繰り返し ~

■ はじめに

https://dk521123.hatenablog.com/entry/2023/03/12/184331

の続き。

Scala で デフォルトでは、break文がないと知ったので
ループに関して調べてみた

目次

【1】ループ
 1)while文
 2)for文
 3)foreach文
【2】便利なメソッド
 1)map
 2)foldLeft / foldRight
 3)zipWithIndex
【3】使用上の注意
【4】トラブル
 1)エラー「value foreach is not a member of java.util.List[XXXX]」発生時

【1】ループ

* 注目すべき Java との違いは、for文の構文が変わった

1)while文

* Java と変わらない

2)for文

for(i <- 1 to 3){
  println(i)
}

var array = Array(1, 2, 3)
for (x <- array) {
  println(x)
}

注意点:Javaとの違い

// () -> {} でもOK

object  Hello {
  def main(args: Array[String]): Unit = {
    // for { i <- 1 to 3 }
    for {
      i <- 1 to 3
    } println(s"i = ${i}")
  }
}

for yield

* 以下の関連記事を参照のこと

https://dk521123.hatenablog.com/entry/2023/09/06/232921

3)foreach文

(1 to 3).foreach( i => println(i))

var array = Array(1, 2, 3)
(array).foreach( x => println(x))

【2】便利なメソッド

1)map

* 各要素に対して処理を行い、その結果を返すメソッド

ループ処理をする方法は?mapメソッドの使い方|Scalapedia
用途

* 各要素を変換するために使用

サンプル

object Hello {
  def main(args: Array[String]): Unit = {
    val array = Array(1, 2, 3, 4, 5)
    val results = array.map(x => x * 2)
    results.foreach(value => println(s"result = ${value}"))
  }
}

出力結果

result = 2
result = 4
result = 6
result = 8
result = 10

2)foldLeft / foldRight

* 畳み込む機能(例えば、階乗)
 + foldLeft : 左から右に走査する
 + foldRight : 右から左に走査する

https://dev.classmethod.jp/articles/scala-foldright-foldleft/
https://zenn.dev/smzst/articles/e7150c88c0d927

構文

// def foldLeft[B](z: B)(op: (B, A) => B): B
// z: 初期値 (0: Int)
// op の第一引数が accumulator (sum)、第二引数が各値 (x ... 1,2,3)
Seq(1, 2, 3).foldLeft(0: Int)((sum, x) => x + sum)
// 6

サンプル

object Hello {
  def main(args: Array[String]): Unit = {
    val array = Array(1, 2, 3, 4, 5)
    // 階乗
    val result1 = array.foldLeft(1) {
      (accumulation, value) => accumulation * value
    }
    // 120
    println(result1)
    println(array.product)

    // 合計
    val result2 = array.foldLeft(0) {
      (sum, value) => sum + value
    }
    // 15
    println(result2)
    println(array.sum)
  }
}

3)zipWithIndex

* インデックス付きのループ

https://qiita.com/takilog/items/f1dfa544580f1a3a6264

サンプル

import java.util.Date
import scala.util.Try

object Hello {
  def main(args: Array[String]): Unit = {
    val targets = Array("2013-07-06", "20130706", "2013.07.06")
    targets.zipWithIndex.foreach {
      case(target:String, index:Int) => {
        val result = getDate(target)
        // [0] Sat Jul 06 00:00:00 JST 2013
        // [1] Sat Jul 06 00:00:00 JST 2013
        // [2] None
        println(s"[${index}] ${result.getOrElse("None")}")
      }
    }
  }

  private def getDate(target: String): Option[Date] = {
    val dateFormats = Array("yyyy/MM/dd", "yyyy-MM-dd", "yyyyMMdd")
    dateFormats.foldLeft[Option[Date]](None) { (parsed, dateFormat) =>
      val format = new java.text.SimpleDateFormat(dateFormat)
      parsed.orElse(Try(format.parse(target)).toOption)
    }
  }
}

【3】使用上の注意

* 冒頭でも書いたが...

[1] break文がデフォルトではない

* ただし、対応案あり。

[2] continue文もない

* 完全にない(実装で工夫するしかない)

break / continue については、以下の関連記事で深堀りする

Scala ~ break / continue ~
https://dk521123.hatenablog.com/entry/2023/10/14/011736

[3] Javaコードのコレクションのループは「import scala.collection.JavaConversions._」が必要

* 詳細は、後述「【4】トラブル」の「1)エラー「・・・」を参照

【4】トラブル

1)エラー「value foreach is not a member of java.util.List[XXXX]」発生時

https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/s3/src/main/java/com/example/s3/S3ObjectOperations.java

を参考に Scala コードで書き直していたら、
以下「エラー発生コード」の★の場所で
以下「エラー内容」が表示された

エラー発生コード

// See https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html
val listObjResponse = s3Client.listObjectsV2(listObjectsReqManual)

// See https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/model/S3Object.html
for (content <- listObjResponse.contents()) { // ★ここでエラー★

エラー内容

value foreach is not a member of
 java.util.List[software.amazon.awssdk.services.s3.model.S3Object]

対応案

コードの冒頭に
import scala.collection.JavaConversions._
を付与する

https://github.com/sryza/aas/issues/20

関連記事

Scala ~ 環境構築編 ~
https://dk521123.hatenablog.com/entry/2023/03/10/193805
Scala ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/03/12/184331
Scala ~ 基本編 / Option型 ~
https://dk521123.hatenablog.com/entry/2023/03/09/000000
Scala ~ 基本編 / メソッド ~
https://dk521123.hatenablog.com/entry/2023/03/03/000000
Scala ~ 基本編 / クラス ~
https://dk521123.hatenablog.com/entry/2023/03/14/000857
Scala ~ 基本編 / コレクション ~
https://dk521123.hatenablog.com/entry/2023/03/13/000345
Scala ~ 基本編 / 日付・日時 ~
https://dk521123.hatenablog.com/entry/2023/03/08/000000
Scala ~ 基本編 / 正規表現
https://dk521123.hatenablog.com/entry/2023/03/18/034704
Scala ~ 基本編 / ジェネリック
https://dk521123.hatenablog.com/entry/2023/03/21/003817
Scala ~ break / continue ~
https://dk521123.hatenablog.com/entry/2023/10/14/011736
Scala ~ for yield ~
https://dk521123.hatenablog.com/entry/2023/09/06/232921
Scala ~ ファイル名・パスの扱い ~
https://dk521123.hatenablog.com/entry/2023/03/11/000000
ScalaYAML
https://dk521123.hatenablog.com/entry/2023/03/16/012034
Spark/Scalaの開発環境構築 ~ Windows編 ~
https://dk521123.hatenablog.com/entry/2023/03/20/115450
SBT ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/03/22/000000