■ はじめに
https://dk521123.hatenablog.com/entry/2023/03/13/000345
の続き。 Scala を勉強してて、コレクションの操作がちゃんと分かっていないと 話にならなそうなので、基本事項をまとめる
目次
【00】コレクション変換のコツ 【01】foreach / zipWithIndex 【02】map 【03】collect 【04】find 【05】takeWhile 【06】dropWhile 【07】span 【08】filter / filterNot 【09】partition 【10】groupBy 【11】forall 【12】exists 【13】count 【14】flatten / flatMap
【00】コレクション変換のコツ
メソッド | 説明 |
---|---|
map | 元の要素と変換先の要素が1:1に対応する時 |
flatMap | 元の要素一つに変換先の要素が0からn個に対応する時 |
filter/filterNot | 元の要素の内、条件に合致する/しないものを取り除きたい時 |
take/takeWhile/dropRight | 元のコレクションの前方からいくつかの要素を取り出したい時 |
drop/dropWhile/takeRight | 元のコレクションの後方からいくつかの要素を取り出したい時 |
++演算子/:::演算子 | 2つのコレクションを繋ぎ合わせたい時 |
【01】foreach / zipWithIndex
* 繰り返し => Mapの場合、タプルで返され、Keyは、x._1、Valueは、x._2 となる * zipWithIndex は、インデックス付き(例3参照)
https://docs.scala-lang.org/scala3/book/collections-methods.html#foreach
サンプル
例1:Array with foreach
object Hello { def main(args: Array[String]): Unit = { val nameList = Array("Mike", "Tom", "Sam") //nameList.foreach(println) //nameList.foreach(println _) //nameList.foreach(println(_)) //nameList.foreach((x: Any) => println(x)) nameList.foreach(x => println(x)) } }
例2:Map with foreach
val sampleMap = Map("x1" -> "Mike", "x2" -> "Tom") // for for ((k,v) <- sampleMap) print(s"key: $k, value: $v / ") println("\n**********") // foreach => Mapの場合、タプルで返され、Keyは、x._1、Valueは、x._2 となる sampleMap.foreach(pair => print(s"key: ${pair._1}, value: ${pair._2} / ")) println("\n**********") sampleMap.foreach { case (key, value) => if (value == "Tom") { print(s"key: $key, value: $value") } } println("\n**********")
例3:Map with foreach - 別解: key/value
https://dk521123.hatenablog.com/entry/2024/07/23/193246
// より抜粋 mapper.foreach { case (key: String, value: ConfigType) => println(s"${key} - ${toPrintStr(value)}") }
https://stackoverflow.com/questions/8610776/scala-map-foreach
例4:zipWithIndex
object Hello { def main(args: Array[String]): Unit = { val sampleList = Array("x1", "x2", "x3") sampleList.zipWithIndex.foreach { case(x: String, i:Int) => println(i, x) } val sampleMap = Map("x1" -> "Mike", "x2" -> "Tom") sampleMap.zipWithIndex.foreach { case(x: (String, String), i:Int) => println(i, x._1, x._2) } } }
https://alvinalexander.com/scala/create-iterating-scala-string-maps/
https://www.baeldung.com/scala/iterate-map
【02】map
* 要素を加工する
https://docs.scala-lang.org/ja/overviews/collections/maps.html
サンプル
例1:For List
import scala.io.Source import java.nio.file.{Paths, Files} import java.nio.charset.StandardCharsets object Hello { def main(args: Array[String]): Unit = { val nameList = Array("Mike", "Tom", "Sam") //val result1s = nameList.map(_.toLowerCase()) //val result2s = nameList.map((x) => x.toLowerCase()) //val result3s = nameList.map(x => x.toLowerCase()) val results = nameList.map((x: String) => x.toLowerCase()) results.foreach(println) } }
例2:For Map, To convert Map to another Map
object Hello { def main(args: Array[String]): Unit = { val mapper = Map("A" -> "1", "B" -> "2", "C" -> "3") // To convert Map[String, String] to another map - Map[String, Int] val anotherMapper: Map[String, Int] = mapper.map{ case(key, value) => (key, value.toInt) } // Output anotherMapper.foreach { case(key, value) => println(s"${key} - ${value}") } } }
【03】collect
* マッチした要素を書こう
サンプル
import scala.io.Source import java.nio.file.{Paths, Files} import java.nio.charset.StandardCharsets object Hello { def main(args: Array[String]): Unit = { val nameList = Array("Mike", "Tom", "Sam") val results = nameList.collect { case "Mike" => "Hi, Mike" case x => x } results.foreach(println) } }
【04】find
* 見つけた要素を返す
サンプル
import scala.io.Source import java.nio.file.{Paths, Files} import java.nio.charset.StandardCharsets object Hello { def main(args: Array[String]): Unit = { val numberList = Array(1, 2, 3, 4, 5) // 最初に条件は true になったものを Some で返す(なければ None) println(numberList.find(x => x % 2 != 0)) // Some(1) println(numberList.find(x => x % 2 == 0)) // Some(2) println(numberList.find(_ <= 0)) // None } }
【05】takeWhile
* 先頭から条件を満たしている間を抽出する
https://scala-text.github.io/scala_text/collection.html
https://qiita.com/suzuki-hoge/items/7cf2e4989a4e860e923f
サンプル
object Hello { def main(args: Array[String]): Unit = { val numberList = Array(1, 2, 3, 4, 5, 4, 3, 2, 1) val results = numberList.takeWhile(_ < 4) println(results.mkString(", ")) // 1, 2, 3 } }
【06】dropWhile
* 先頭から条件を満たしている間を除外する
サンプル
object Hello { def main(args: Array[String]): Unit = { val numberList = Array(1, 2, 3, 4, 5, 4, 3, 2, 1) val results = numberList.dropWhile(_ < 4) println(results.mkString(", ")) // 4, 5, 4, 3, 2, 1 } }
【07】span
* 先頭から条件を満たしている間の要素を2分割する
https://www.baeldung.com/scala/split-sequence
サンプル
object Hello { def main(args: Array[String]): Unit = { val numberList = Array(1, 2, 3, 4, 5, 4, 3, 2, 1) val (result1s, result2s) = numberList.span(_ < 4) println(result1s.mkString(",")) // 1,2,3 println(result2s.mkString(",")) // 4,5,4,3,2,1 } }
【08】filter / filterNot
* 条件に一致・不一致した要素を抽出する
https://stackoverflow.com/questions/27942480/using-regex-with-filter-in-scala
サンプル
例1:空文字を除外する
object Hello { def main(args: Array[String]): Unit = { println("Start") val targetList = List("Start", "", "Hello", "", "World", "End") val results = targetList.filter(x => x.nonEmpty) println(s"Done. ${results.mkString(",")}") // Done. Start,Hello,World,End } }
例2:正規表現でフィルタリングする
object Hello { def main(args: Array[String]) { println("Start") val targetList = Seq("a12345", "b123456", "aaaa1111", "123456", "xxxxxxx") // 【文字列】【6桁数字】 val regex = """^([a-zA-Z]\d{6})""".r val results = targetList.filter { x => regex.findFirstIn(x).isDefined } println(s"Done. ${results}") // List(b123456) } }
【09】partition
* 条件で2分割する
サンプル
object Hello { def main(args: Array[String]): Unit = { val numberList = Array(1, 2, 3, 4, 5, 4, 3, 2, 1) val (result1s, result2s) = numberList.partition(_ < 4) println(result1s.mkString(",")) // 1,2,3,3,2,1 println(result2s.mkString(",")) // 4,5,4 } }
【10】groupBy
* 要素を分類する
サンプル
object Hello { def main(args: Array[String]): Unit = { val numberList = Array(1, 2, 3, 4, 5, 4, 3, 2, 1) // Map[] で値を返す val results = numberList.groupBy(_ < 4) for ((key, values: Array[Int]) <- results) { val value = values.mkString(",") println(s"${key}: ${value}") } } }
出力結果
true: 1,2,3,3,2,1 false: 4,5,4
【11】forall
* 要素全体をチェックし、 全ての要素が合致していれば、true(それ以外は false)を返す
サンプル
object Hello { def main(args: Array[String]): Unit = { val numberList = Array(1, 2, 3, 4, 5, 4, 3, 2, 1) // 全ての要素が合致していれば、true val isTrue = numberList.forall(_ > 0) println(s"result = ${isTrue}") // result = true // 全ての要素が合致していないので、false val isFalse = numberList.forall(_ > 1) println(s"result = ${isFalse}") // result = false } }
【12】exists
* 合致する要素の存在をチェックし、 要素が存在すれば、true(それ以外は false)を返す
サンプル
object Hello { def main(args: Array[String]): Unit = { val numberList = Array(1, 2, 3, 4, 5, 4, 3, 2, 1) // 要素が存在すれば、true val isTrue = numberList.exists(_ != 5) println(s"result = ${isTrue}") // result = true // 要素が存在していないので、false val isFalse = numberList.exists(_ > 8) println(s"result = ${isFalse}") // result = false } }
【13】count
* 合致する要素をカウントする
サンプル
object Hello { def main(args: Array[String]): Unit = { val numberList = Array(1, 2, 3, 4, 5, 4, 3, 2, 1) val resultFor3 = numberList.count(_ == 3) println(s"result = ${resultFor3}") // result = 2 val resultForOver8 = numberList.count(_ > 8) println(s"result = ${resultForOver8}") // result = 0 } }
【14】flatten / flatMap
flatten
* コレクションの要素がネストしている場合に 平坦(Flat)にするために使用
flatMap
* mapしてから、flattenする
参考文献
https://qiita.com/f81@github/items/62ad3c56ce6be271ef35
関連記事
Scala ~ 環境構築編 ~
https://dk521123.hatenablog.com/entry/2023/03/10/193805
Scala ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/03/12/184331
Scala ~ 基本編 / コレクション ~
https://dk521123.hatenablog.com/entry/2023/03/13/000345
Scala ~ mutable collection ~
https://dk521123.hatenablog.com/entry/2024/07/09/223730
Scala ~ 部分関数 / PartialFunction ~
https://dk521123.hatenablog.com/entry/2023/09/08/235546
Scala ~ 代数的データ型 / ADT ~
https://dk521123.hatenablog.com/entry/2024/07/23/193246