list 将 Scala 列表转换为元组?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14722860/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Convert a Scala list to a tuple?
提问by grautur
How can I convert a list with (say) 3 elements into a tuple of size 3?
如何将具有(例如)3 个元素的列表转换为大小为 3 的元组?
For example, let's say I have val x = List(1, 2, 3)
and I want to convert this into (1, 2, 3)
. How can I do this?
例如,假设我有val x = List(1, 2, 3)
并且我想将其转换为(1, 2, 3)
. 我怎样才能做到这一点?
采纳答案by Tom Crockett
You can't do this in a typesafe way. Why? Because in general we can't know the length of a list until runtime. But the "length" of a tuple must be encoded in its type, and hence known at compile time. For example, (1,'a',true)
has the type (Int, Char, Boolean)
, which is sugar for Tuple3[Int, Char, Boolean]
. The reason tuples have this restriction is that they need to be able to handle a non-homogeneous types.
您不能以类型安全的方式执行此操作。为什么?因为通常我们直到运行时才能知道列表的长度。但是元组的“长度”必须以其类型编码,因此在编译时就知道了。例如,(1,'a',true)
具有类型(Int, Char, Boolean)
,它是 的糖Tuple3[Int, Char, Boolean]
。元组有这个限制的原因是它们需要能够处理非同构类型。
回答by cyrillk
You can do it using scala extractors and pattern matching (link):
您可以使用 Scala 提取器和模式匹配(链接)来做到这一点:
val x = List(1, 2, 3)
val t = x match {
case List(a, b, c) => (a, b, c)
}
Which returns a tuple
返回一个元组
t: (Int, Int, Int) = (1,2,3)
Also, you can use a wildcard operator if not sure about a size of the List
此外,如果不确定列表的大小,您可以使用通配符运算符
val t = x match {
case List(a, b, c, _*) => (a, b, c)
}
回答by evantill
an example using shapeless:
一个使用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
Note: the compiler need some type informations to convert the List in the HList that the reason why you need to pass type informations to the toHList
method
注意:编译器需要一些类型信息来转换 HList 中的 List,这就是为什么需要将类型信息传递给toHList
方法的原因
回答by virtualirfan
Shapeless 2.0changed some syntax. Here's the updated solution using shapeless.
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
The main issue being that the type for .toHListhas to be specified ahead of time. More generally, since tuples are limited in their arity, the design of your software might be better served by a different solution.
主要问题是.toHList的类型必须提前指定。更普遍的是,由于元组的数量有限,因此不同的解决方案可能会更好地为您的软件设计提供服务。
Still, if you are creating a list statically, consider a solution like this one, also using shapeless. Here, we create an HList directly and the type is available at compile time. Remember that an HList has features from both List and Tuple types. i.e. it can have elements with different types like a Tuple and can be mapped over among other operations like standard collections. HLists take a little while to get used to though so tread slowly if you are new.
不过,如果您要静态创建列表,请考虑这样的解决方案,也使用 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)
回答by virtualirfan
Despite the simplicity and being not for lists of any length, it is type-safe and the answer in most cases:
尽管简单且不适合任何长度的列表,但它是类型安全的,并且在大多数情况下是答案:
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))
Another possibility, when you don't want to name the list nor to repeat it (I hope someone can show a way to avoid the Seq/head parts):
另一种可能性,当您不想命名列表或重复它时(我希望有人可以展示一种避免 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
回答by Peter L
FWIW, I wanted a tuple to initalise a number of fieldsand wanted to use the syntactic sugar of tuple assignment. EG:
FWIW,我想要一个元组来初始化多个字段,并想使用元组分配的语法糖。例如:
val (c1, c2, c3) = listToTuple(myList)
It turns out that there is syntactic sugar for assigning the contents of a list too...
事实证明,也有用于分配列表内容的语法糖......
val c1 :: c2 :: c3 :: Nil = myList
So no need for tuples if you've got the same problem.
因此,如果您遇到同样的问题,则不需要元组。
回答by Mechanical snail
You can't do this in a type-safe way. In Scala, lists are arbitrary-lengthsequences of elements of some type. As far as the type system knows, x
could be a list of arbitrary length.
您不能以类型安全的方式执行此操作。在 Scala 中,列表是某种类型元素的任意长度序列。据类型系统所知,x
可以是任意长度的列表。
In contrast, the arity of a tuple must be known at compile time. It would violate the safety guarantees of the type system to allow assigning x
to a tuple type.
相比之下,元组的数量必须在编译时知道。允许分配x
给元组类型将违反类型系统的安全保证。
In fact, for technical reasons, Scala tuples were limited to 22 elements, but the limit no longer exists in 2.11 The case class limit has been lifted in 2.11 https://github.com/scala/scala/pull/2305
事实上,由于技术原因,Scala元组被限制为22个元素,但2.11中不再存在该限制在2.11中取消了case类限制https://github.com/scala/scala/pull/2305
It would be possible to manually code a function that converts lists of up to 22 elements, and throws an exception for larger lists. Scala's template support, an upcoming feature, would make this more concise. But this would be an ugly hack.
可以手动编写一个函数来转换最多 22 个元素的列表,并为更大的列表抛出异常。Scala 的模板支持,即将推出的功能,将使这更简洁。但这将是一个丑陋的黑客。
回答by Kolmar
This can also be done in shapeless
with less boilerplate using Sized
:
这也可以shapeless
使用更少的样板来完成Sized
:
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))
It's type-safe: you get None
, if the tuple size is incorrect, but the tuple size must be a literal or final val
(to be convertible to shapeless.Nat
).
它是类型安全的:None
如果元组大小不正确,则会得到,但元组大小必须是文字或final val
(可转换为shapeless.Nat
)。
回答by Spark-Beginner
If you are very sure that your list.size<23 use it:
如果您非常确定您的 list.size<23 使用它:
def 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)
回答by Michael Olafisoye
Using Pattern Matching:
使用模式匹配:
val intTuple = List(1,2,3) match {case List(a, b, c) => (a, b, c)}
val intTuple = List(1,2,3) 匹配 {case List(a, b, c) => (a, b, c)}