DBから外部結合したクエリーの結果をcase class
のSeq
に格納し、その後のプログラムで扱いやすいように加工した時の備忘録です。
case class定義
DBから取得時のcase class
case class DBItem(
id : Int,
name : String,
optionId : Option[Int],
optionName : Option[String]
)
加工後のcase class
case class Item(
id : Int,
name : String,
options : Map[Int, String] = Map.empty[Int, String]
)
groupBy処理
DBから取得したデータは、下記のような形式でSeq
に格納されているとします。
val dbItems = Seq(
DBItem(1, "item1", Some("1"), Some("opt1")),
DBItem(1, "item1", Some("2"), Some("opt1")),
DBItem(2, "item2", None, None)
)
最初に可読性も悪く、非効率なコードを書いてしまったので、前後のコードを載せておきます。
リファクタリング後
dbItems.groupBy(_.id).mapValues {
items => Item(
id = items.head.id,
name = items.head.name,
options = items.collect {
case DBItem(_, _, Some(id), Some(name)) => id -> name
} toMap
)
}
リファクタリング前
dbItems.groupBy(_.id).map {
case (id, item) =>
id ->
item.groupBy(_.name).map {
case (name, options) =>
Item(
id = id,
name = name,
options = options.filter { opt =>
opt.optionId.isDefined && opt.optionName.isDefined
} map { opt =>
opt.optionId.get -> opt.optionName.get
} toMap
)
}.head
}
結果
scala.collection.immutable.Map[Int,Item] = Map(
2 -> Item(2,item2,Map()),
1 -> Item(1,item1,Map(1 -> option1, 2 -> option2))
)
どちらも同一の求める結果となりました。
振り返り
-
filter
とmap
を続けて書く時は、collect
を適用できないか考える -
map
後にhead
のように違和感がある時は、やはり良くない書き方になっている気がする - パターンマッチと
case class
をもっと使いこなす
といったところが、自分の足りないところだと思いました。