Sometimes there are needs to create tuples from small collections(for example scalding framework).
def toTuple(list:List[Any]):scala.Product = ...
You really don't want your method to return Product
since this is uselessly vague. If you want to be able to use the returned object as a tuple, then you'll have to know its arity. So what you can do is have a series of toTupleN
methods for different arities. For convenience, you can add these as implicit methods on Seq
.
How about this:
class EnrichedWithToTuple[A](elements: Seq[A]) {
def toTuple2 = elements match { case Seq(a, b) => (a, b) }
def toTuple3 = elements match { case Seq(a, b, c) => (a, b, c) }
def toTuple4 = elements match { case Seq(a, b, c, d) => (a, b, c, d) }
def toTuple5 = elements match { case Seq(a, b, c, d, e) => (a, b, c, d, e) }
}
implicit def enrichWithToTuple[A](elements: Seq[A]) = new EnrichedWithToTuple(elements)
and use it like:
scala> List(1,2,3).toTuple3
res0: (Int, Int, Int) = (1,2,3)
If, as @dhg observed, you know the expected arity up front you can do something useful here. Using shapeless you could write,
scala> import shapeless._
import shapeless._
scala> import Traversables._
import Traversables._
scala> import Tuples._
import Tuples._
scala> List(1, 2, 3).toHList[Int :: Int :: Int :: HNil] map tupled
res0: Option[(Int, Int, Int)] = Some((1,2,3))
If you don't know the arity up front and want to do a terrible terrible hack, you can do this:
def toTuple[A <: Object](as:List[A]):Product = {
val tupleClass = Class.forName("scala.Tuple" + as.size)
tupleClass.getConstructors.apply(0).newInstance(as:_*).asInstanceOf[Product]
}
toTuple: [A <: java.lang.Object](as: List[A])Product
scala> toTuple(List("hello", "world"))
res15: Product = (hello,world)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With