Подтвердить что ты не робот

Есть ли способ создать кортеж из списка (без кодирования)?

Иногда возникает необходимость в создании кортежей из небольших коллекций (например, обжигающая система).

def toTuple(list:List[Any]):scala.Product = ...
4b9b3361

Ответ 1

Если вы не знаете арности впереди и хотите сделать страшный ужасный взлом, вы можете сделать это:

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)

Ответ 2

Вы действительно не хотите, чтобы ваш метод возвращал 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)

Ответ 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))

Ответ 4

Вы хотите 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): _*)

Ответ 5

Основываясь на идее @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: _*)
  }

}