In Scala, is there an easy way to convert a case class into a tuple?
ScalaTuplesCase ClassScala Problem Overview
Is there an easy way to convert a case class into a tuple?
I can, of course, easily write boilerplate code to do this, but I mean without the boilerplate.
What I'm really after is a way to easily make a case class lexicographically Ordered. I can achieve the goal for tuples by importing scala.math.Ordering.Implicits._, and voila, my tuples have an Ordering defined for them. But the implicits in scala.math.Ordering don't work for case classes in general.
Scala Solutions
Solution 1 - Scala
How about calling unapply().get
in the companion object?
case class Foo(foo: String, bar: Int)
val (str, in) = Foo.unapply(Foo("test", 123)).get
// str: String = test
// in: Int = 123
Solution 2 - Scala
Shapeless will do this for you.
import shapeless._
import shapeless.syntax.std.product._
case class Fnord(a: Int, b: String)
List(Fnord(1, "z - last"), Fnord(1, "a - first")).sortBy(_.productElements.tupled)
Gets
res0: List[Fnord] = List(Fnord(1,a - first), Fnord(1,z - last))
productElements turns a case class into a Shapeless HList:
scala> Fnord(1, "z - last").productElements
res1: Int :: String :: shapeless.HNil = 1 :: z - last :: HNil
And HLists are converted to tuples with #tupled:
scala> Fnord(1, "z - last").productElements.tupled
res2: (Int, String) = (1,z - last)
Performance is likely to be horrible, since you're constantly converting. You'd probably convert everything to the tupled form, sort that, then convert it back using something like (Fnord.apply _).tupled
.
Solution 3 - Scala
Came across this old thread while attempting to do this same thing. I eventually settled on this solution:
case class Foo(foo: String, bar: Int)
val testFoo = Foo("a string", 1)
val (str, in) = testFoo match { case Foo(f, b) => (f, b) }
Solution 4 - Scala
You might try extending the ProductN
trait, for N=1-22, which TupleN
extends. It will give you a lot of Tuple semantics, like the _1
, _2
, etc. methods. Depending on you how you use your types, this might be sufficient without creating an actual Tuple.
Solution 5 - Scala
Scala 3 has first class support for conversions between case classes and tuples:
scala> case class Foo(foo: String, bar: Int)
// defined case class Foo
scala> Tuple.fromProductTyped(Foo("a string", 1))
val res0: (String, Int) = (a string,1)
scala> summon[deriving.Mirror.ProductOf[Foo]].fromProduct(res0)
val res1: deriving.Mirror.ProductOf[Foo]#MirroredMonoType = Foo(a string,1)