Scalaアレコレ2019

Option型の変数に任意の値が入っているかどうかで処理を分岐させる

/*
 * 以下のようなcase classがあって、HogeがMasterHogeにOption型として格納される場合に、
 * HogeのメンバフィールドであるOption型のisHoge(フラグ的なもの)の値をチェックする
 */
case class MasterHoge(
  hoge: Option[Hoge] = None
) 
case class Hoge(
  isHoge: Option[Int] = None
)

// どこかでMasterHogeをインスタンス化
val masterHoge = xxxx

// foreachとcontainsを使う
masterHoge.foreach { hoge =>
      if (hoge.isHoge.contains(1)) {
        // ココに行いたい処理を書く
      }
    }

zipWithIndex()を使ってSeqのインデックスと要素にアクセスする

  val hogeSeq = Seq("a", "b", "c", "d", "e")

  hogeSeq.zipWithIndex.foreach{case(value, index) => {
    printf("${index}:${value}") // 0:a 1:b 2:c ....
  }}

groupBy()を使ってMapのListを1つのMapにまとめる

  // ↓このようなMapのListがあったとして、これを"id"をキーとしたMapにまとめたいとする
  val hogeList = List(
    Map[String, Int](
      "id" -> 1,
      "vid" -> 2,
      "value" -> 10
    ),
    Map[String, Int](
      "id" -> 2,
      "vid" -> 4,
      "value" -> 20
    ),
    Map[String, Int](
      "id" -> 1,
      "vid" -> 21,
      "value" -> 17
    ),
  )

  // "value"の降順で上記のListを並べ替えたListを作る(これは本題とは関係のない操作)
  val sortedList = hogeList.sortBy(_.get("value"))(Ordering[Option[Int]].reverse)

  val hoshiimono = sortedList.groupBy(ho => {
    ho.get("id").get
  }).map(h => {
    val list = h._2
    h._1 -> list.map(l => {
      l.get("vid").get
    })
  })

  printf(s"___ ${hosiimono} ___")
  /* 結果
     Map(2 -> List(4), 1 -> List(21, 2))
   */

処理実行元のディレクトリを取得

sys.props("usr.dir")

文字列の前後にあるダブルクォーテーションを削除

以下のような形式のJSONJSON文字列的にparseしようとしたら構文エラーとなってしまった。

"{\"hoge\":{…}…, \"hogehoge\":\"geho\"}"

最初と最後にダブルクォーテーションが入っているのが原因だったので、以下のようにして取り除いた。

// まずエスケープとして入ってしまっていたバックスラッシュを取り除く
val jsonDataWithoutEscape = StringContext treatEscapes(jsonData.toString())

// 頭と後ろのダブルクォーテーションを削除
val jsonStr = jsonDataWithoutEscape.dropWhile( _ == '"' ).reverse.dropWhile( _ == '"' ).reverse

Jacksonを用いて複数階層を掘り下げつつ不要な要素を削除する

処理の流れ
  1. Json文字列からObjectNodeを生成
  2. ObjectNodeから削除したいfieldに対してremoveを実行
  3. 返されたJsonNodeからObjectNodeを生成
  4. 階層に応じて上記02〜03を繰り返す
ソースコード
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.node.ObjectNode

val jsonStr =
"""{"A":{.....}, "child":{"B":{}, "child":{....}, ....}} // 「親→子1→子2」の3世代
""".stripMargin

val parentObjectNode = mapper.readTree(jsonStr).asInstanceOf[ObjectNode]
val child1JsonNode     = parentObjectNode.remove("child") // 戻り値としてAが返され、parentObjectNodeからchildが削除される
val child1ObjectNode  = mapper.readTree(childJsonNode.get(0).toString).asInstanceOf[ObjectNode]
val child2JsonNode     = child1ObjectNode.remove("child")

文字列を区切り文字で区切って配列にしたり等

  val moji = "hoge:hohoge, geho:gegeho"
  val arr1 = moji.split(",")
  val hoge = arr1.map ( a=> {
    val arrlast = a.split(":")
    Map(arrlast(0) -> arrlast(1))
  })
  log.info(s"### ${hoge(0)} ###")
更に文字列の中身が数値だったらInt型に、そうでなければ文字列のままにしておく処理
      val attributes = mojiretsu match {
        case Some(attr) => {
          val arr = attr.split(":")
          val value = try {
            arr(1).trim.toInt
          } catch {
            case _:NumberFormatException => arr(1).trim
          }
          Map(arr(0)->value)
        }
        case _ => Map[String, Any]()
      }