scala で Java コレクションの「デコンストラクタ」を作成しようとしています。
ほとんどの scala コレクションでは、::
case クラスを使用してコレクションを head/tail で分解できます。
scala> val (a :: b) = Seq(1,2)
a: Int = 1
b: List[Int] = List(2)
scala> val (a :: b :: Nil) = Seq(1,2)
a: Int = 1
b: Int = 2
さらに複雑なケース (例: 内部リストの最初の 2 つの要素の合計):
scala> val m = Map("a" -> Seq(1,2,3,4), "b" -> Seq(2,3,4,5))
scala> m.collect { case (k, a :: b :: _) => k ->(a+b)}
res5: scala.collection.immutable.Map[java.lang.String,Int] = Map(a -> 3, b -> 5)
しかし、余分なコードなしでJavaコレクションに対してこれを機能させる方法を理解することはできません:
外部ライブラリから次のようなものを取得するとしましょう:
m: java.util.Map[java.lang.String,java.util.List[Int]] = {a=[1, 2, 3, 4], b=[2, 3, 4, 5]}
scala<=>java コレクション変換を使用して、マップを scala マップに変換し、まだ Java であるリスト内で作業できます。
m.asScala.collect { case (k, jl) => jl.asScala.toList match { case (a :: b :: _) => k->(a+b) } }
また
m.asScala.map{
case (k, v) => k -> v.asScala.toList
}.collect {
case (k, a :: b :: _) => k ->(a+b)
}
マッチャーのトリックを見つけましたunapplySeq
が、これはコレクションのサイズがわかっている場合にのみ機能します。
object JavaCollection {
import scala.collection.JavaConverters._
def unapplySeq[T](array: java.util.Collection[T]): Option[Seq[T]] = Option(array).map(_.asScala.toIndexedSeq)
}
m.asScala.collect { case (k, JavaCollection(a,b,c,d)) => k ->(a+b)}
::
明示的な変換を行わずに、Java 型付きコレクションで直接分解を行うにはどうすればよいですか? 独自のcase class ::[T](head:T, tail: java.util.Collection[T])
クラスを作成しようとしましたが、それだけでは十分ではないようです。