Scala 목록을 튜플로 변환 하시겠습니까?
3 개의 요소가있는 목록을 크기 3의 튜플로 어떻게 변환 할 수 있습니까?
예를 들어, 내가 가지고 val x = List(1, 2, 3)
있고 이것을 (1, 2, 3)
. 어떻게 할 수 있습니까?
형식이 안전한 방식으로는이 작업을 수행 할 수 없습니다. 왜? 일반적으로 우리는 런타임까지 목록의 길이를 알 수 없기 때문입니다. 그러나 튜플의 "길이"는 해당 유형으로 인코딩되어야하며 따라서 컴파일 타임에 알려 져야합니다. 예를 들어 (1,'a',true)
에는 유형 (Int, Char, Boolean)
이 Tuple3[Int, Char, Boolean]
있습니다. 튜플에 이러한 제한이있는 이유는 비 동종 유형을 처리 할 수 있어야하기 때문입니다.
스칼라 추출기와 패턴 일치를 사용하여 수행 할 수 있습니다 ( 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)
또한 List의 크기가 확실하지 않은 경우 와일드 카드 연산자를 사용할 수 있습니다.
val t = x match {
case List(a, b, c, _*) => (a, b, c)
}
형태없는 사용 예 :
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
참고 : 컴파일러는 HList의 List를 변환하기 위해 몇 가지 유형 정보가 필요하므로 유형 정보를 toHList
메서드에 전달해야하는 이유
Shapeless 2.0 은 일부 구문을 변경했습니다. 무형을 사용하는 업데이트 된 솔루션은 다음과 같습니다.
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 의 유형을 미리 지정해야한다는 것입니다. 일반적으로 튜플은 배열이 제한되어 있으므로 소프트웨어 디자인은 다른 솔루션에서 더 잘 제공 될 수 있습니다.
그래도 정적으로 목록을 만드는 경우에는 모양이없는 것을 사용하는 이와 같은 솔루션을 고려하십시오. 여기에서 HList를 직접 생성하고 컴파일 타임에 유형을 사용할 수 있습니다. HList에는 List 및 Tuple 유형의 기능이 있습니다. 즉, 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
따라서 동일한 문제가 발생하면 튜플이 필요하지 않습니다.
형식이 안전한 방식으로는이 작업을 수행 할 수 없습니다. Scala에서 목록은 어떤 유형의 요소의 임의 길이 시퀀스입니다. 유형 시스템이 아는 x
한 임의의 길이 목록이 될 수 있습니다.
반대로, 튜플의 배열은 컴파일 타임에 알아야합니다. x
튜플 유형에 할당 을 허용하는 유형 시스템의 안전 보장을 위반합니다 .
사실 기술적 인 이유로 스칼라 튜플 은 22 개 요소로 제한되었지만 2.11에서는 더 이상 존재하지 않습니다. 케이스 클래스 제한은 2.11에서 해제되었습니다. 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.
This can also be done in shapeless
with less boilerplate using 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
).
If you are very sure that your list.size<23 use it:
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)
as far as you have the type:
val x: List[Int] = List(1, 2, 3)
def doSomething(a:Int *)
doSomething(x:_*)
2015 post. For the Tom Crockett's answer to be more clarifying, here is a real example.
At first, I got confused about it. Because I come from Python, where you can just do tuple(list(1,2,3))
.
Is it short of Scala language ? (the answer is -- it's not about Scala or Python, it's about static-type and dynamic-type.)
That's causes me trying to find the crux why Scala can't do this .
The following code example implements a toTuple
method, which has type-safe toTupleN
and type-unsafe toTuple
.
The toTuple
method get the type-length information at run-time, i.e no type-length information at compile-time, so the return type is Product
which is very like the Python's tuple
indeed (no type at each position, and no length of types).
That way is proned to runtime error like type-mismatch or IndexOutOfBoundException
. (so Python's convenient list-to-tuple is not free lunch. )
Contrarily , it is the length information user provided that makes toTupleN
compile-time safe.
implicit class EnrichedWithToTuple[A](elements: Seq[A]) {
def toTuple: Product = elements.length match {
case 2 => toTuple2
case 3 => toTuple3
}
def toTuple2 = elements match {case Seq(a, b) => (a, b) }
def toTuple3 = elements match {case Seq(a, b, c) => (a, b, c) }
}
val product = List(1, 2, 3).toTuple
product.productElement(5) //runtime IndexOutOfBoundException, Bad !
val tuple = List(1, 2, 3).toTuple3
tuple._5 //compiler error, Good!
you can do this either
- via pattern-matching (what you do not want) or
by iterating through the list and applying each element one by one.
val xs: Seq[Any] = List(1:Int, 2.0:Double, "3":String) val t: (Int,Double,String) = xs.foldLeft((Tuple3[Int,Double,String] _).curried:Any)({ case (f,x) => f.asInstanceOf[Any=>Any](x) }).asInstanceOf[(Int,Double,String)]
Using Pattern Matching:
val intTuple = List(1,2,3) match {case List(a, b, c) => (a, b, c)}
참고URL : https://stackoverflow.com/questions/14722860/convert-a-scala-list-to-a-tuple
'code' 카테고리의 다른 글
Field Injection이란 정확히 무엇이며 어떻게 피할 수 있습니까? (0) | 2020.10.09 |
---|---|
JSON 결과를 날짜로 변환 (0) | 2020.10.09 |
Maven 리소스 필터링이 작동하지 않음-스프링 부트 종속성으로 인해 (0) | 2020.10.09 |
기능과 레이블의 차이점은 무엇입니까? (0) | 2020.10.09 |
람다 함수 및 매개 변수의 범위? (0) | 2020.10.09 |