Иногда возникает необходимость в создании кортежей из небольших коллекций (например, обжигающая система).
def toTuple(list:List[Any]):scala.Product = ...
Иногда возникает необходимость в создании кортежей из небольших коллекций (например, обжигающая система).
def toTuple(list:List[Any]):scala.Product = ...
Если вы не знаете арности впереди и хотите сделать страшный ужасный взлом, вы можете сделать это:
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)
Вы действительно не хотите, чтобы ваш метод возвращал Product
, поскольку это бесполезно неопределенно. Если вы хотите использовать возвращаемый объект в качестве кортежа, вам нужно будет узнать его арность. Итак, вы можете сделать серию методов toTupleN
для разных явлений. Для удобства вы можете добавить их как неявные методы на Seq
.
Как насчет этого:
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)
и используйте его как:
scala> List(1,2,3).toTuple3
res0: (Int, Int, Int) = (1,2,3)
Если, как заметил @dhg, вы знаете ожидаемую реальность, вы можете сделать что-то полезное здесь. Используя shapeless, вы можете написать
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))
Вы хотите Tuple
или просто Product
. Потому что для последнего:
case class SeqProduct[A](elems: A*) {
override def productArity: Int = elems.size
override def productElement(i: Int) = elems(i)
}
SeqProduct(List(1, 2, 3): _*)
Основываясь на идее @Kim Stebel, я написал простую утилиту, которая создает кортеж из 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: _*)
}
}