如何将一个包含三个元素的列表转换成大小为3的元组?
例如,假设我有val x = List(1, 2, 3)
,我想将其转换为(1, 2, 3)
。我该怎么做?
您可以使用Scala提取器和模式匹配(link)来实现:
val x = List(1, 2, 3)
val t = x match {
case List(a, b, c) => (a, b, c)
}
返回一个元组
t: (Int, Int, Int) = (1,2,3)
val t = x match {
case List(a, b, c, _*) => (a, b, c)
}
由于通常在运行时无法知道列表的长度,因此您无法以类型安全的方式完成此操作。但元组的“长度”必须编码在其类型中,并且因此在编译时已知。例如,(1,'a',true)
具有类型 (Int, Char, Boolean)
,这是 Tuple3[Int, Char, Boolean]
的语法糖。元组具有此限制的原因是它们需要能够处理非同构类型。
case class Vec3[A](_1: A, _2: A, _3: A)
。 - Tom Crockettmap
等。 - Tom Crockett一个使用shapeless的示例:
import shapeless._
import syntax.std.traversable._
val x = List(1, 2, 3)
val xHList = x.toHList[Int::Int::Int::HNil]
val t = xHList.get.tupled
注意:编译器需要一些类型信息将List转换为HList,这就是为什么您需要向toHList
方法传递类型信息的原因。
Shapeless 2.0更改了一些语法。以下是使用shapeless的更新解决方案。
import shapeless._
import HList._
import syntax.std.traversable._
val x = List(1, 2, 3)
val y = x.toHList[Int::Int::Int::HNil]
val z = y.get.tupled
主要问题在于必须事先指定.toHList的类型。更一般地说,由于元组在其度量方面受到限制,您的软件设计可能会通过不同的解决方案得到更好的服务。
不过,如果您正在静态创建列表,请考虑使用此解决方案,同样使用shapeless。 在这里,我们直接创建一个HList,并且类型在编译时可用。请记住,HList具有来自List和Tuple类型的功能。即它可以有不同类型的元素,就像元组一样,并且可以映射等其他操作,就像标准集合一样。不过,需要花费一些时间才能熟悉HLists,因此如果您是新手,请小心谨慎。
scala> import shapeless._
import shapeless._
scala> import HList._
import HList._
scala> val hlist = "z" :: 6 :: "b" :: true :: HNil
hlist: shapeless.::[String,shapeless.::[Int,shapeless.::[String,shapeless.::[Boolean,shapeless.HNil]]]] = z :: 6 :: b :: true :: HNil
scala> val tup = hlist.tupled
tup: (String, Int, String, Boolean) = (z,6,b,true)
scala> tup
res0: (String, Int, String, Boolean) = (z,6,b,true)
尽管它很简单且不适用于任何长度的列表,但它是类型安全的,并且在大多数情况下都是正确的答案:
val list = List('a','b')
val tuple = list(0) -> list(1)
val list = List('a','b','c')
val tuple = (list(0), list(1), list(2))
另一种可能性是,当您不想命名列表或重复它时(我希望有人能展示一种避免Seq/head部分的方法):
val tuple = Seq(List('a','b')).map(tup => tup(0) -> tup(1)).head
val tuple = Seq(List('a','b','c')).map(tup => (tup(0), tup(1), tup(2))).head
顺便说一下,我想要一个元组来 初始化几个字段 ,并且想要使用元组赋值的语法糖。 例如:
FWIW,我想用元组来初始化多个字段,并且希望使用元组赋值的语法糖。
val (c1, c2, c3) = listToTuple(myList)
原来对于将列表内容赋值的操作,还有一种语法糖可用...
val c1 :: c2 :: c3 :: Nil = myList
如果你遇到相同的问题,就不需要使用元组。
val List(c1, c2, c3) = myList
- Kolmardef listToTuple[A <: Object](list:List[A]):Product = {
val class = Class.forName("scala.Tuple" + list.size)
class.getConstructors.apply(0).newInstance(list:_*).asInstanceOf[Product]
}
listToTuple: [A <: java.lang.Object](list: List[A])Product
scala> listToTuple(List("Scala", "Smart"))
res15: Product = (Scala,Smart)
使用Sized
可以在shapeless
中更少地使用样板代码来完成此操作:
scala> import shapeless._
scala> import shapeless.syntax.sized._
scala> val x = List(1, 2, 3)
x: List[Int] = List(1, 2, 3)
scala> x.sized(3).map(_.tupled)
res1: Option[(Int, Int, Int)] = Some((1,2,3))
它是类型安全的:如果元组大小不正确,则会得到None
,但元组大小必须是字面量或final val
(可转换为shapeless.Nat
)。
使用模式匹配:
val intTuple = List(1,2,3) match {case List(a, b, c) => (a, b, c)}
List
/Tuple
的长度是已知常量的情况下,你的答案才适用。 - jwvh
def toTuple(x: List[Int]): R
,R的类型应该是什么? - user166390x match { case a :: b :: c :: Nil => (a, b, c); case _ => (0, 0, 0) }
,注意结果类型固定为Tuple3[Int,Int,Int]
。 - user166390List
无法实现您所需的功能,但您可以尝试使用Shapeless的HList
类型,该类型允许元组之间的转换(http://github.com/milessabin/shapeless#facilities-for-abstracting-over-arity)。也许它适用于您的用例。 - user500592