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) exampleList match { case Seq(a, b, c) => (a, b, c)}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) var List(a,b,c) = myIter.toListDo you want a Tuple or just a Product. Because for the latter:
case class SeqProduct[A](elems: A*) { override def productArity: Int = elems.size override def productElement(i: Int) = elems(i) } SeqProduct(List(1, 2, 3): _*) Tuple, so I could use FunctionX.tupled, which indeed requires a TupleX, not Product (note even ProductX).Based on @Kim Stebel's idea, I wrote a simple utility that creates tuple from seq.
import java.lang.reflect.Constructor /** * Created by Bowen Cai on 1/24/2015. */ sealed trait Product0 extends Any with Product { def productArity = 0 def productElement(n: Int) = throw new IllegalStateException("No element") def canEqual(that: Any) = false } object Tuple0 extends Product0 { override def toString() = "()" } case class SeqProduct(elems: Any*) extends Product { override def productArity: Int = elems.size override def productElement(i: Int) = elems(i) override def toString() = elems.addString(new StringBuilder(elems.size * 8 + 10), "(" , ",", ")").toString() } object Tuples { private[this] val ctors = { val ab = Array.newBuilder[Constructor[_]] for (i <- 1 to 22) { val tupleClass = Class.forName("scala.Tuple" + i) ab += tupleClass.getConstructors.apply(0) } ab.result() } def toTuple(elems: Seq[AnyRef]): Product = elems.length match { case 0 => Tuple0 case size if size <= 22 => ctors(size - 1).newInstance(elems: _*).asInstanceOf[Product] case size if size > 22 => new SeqProduct(elems: _*) } } size<=22 with val refs = for (e <- elems) yield e.asInstanceOf[AnyRef] ctors(size - 1).newInstance(refs: _*).asInstanceOf[Product] (based on the answer here: [link] (stackoverflow.com/questions/16751484/…))