[list] 스칼라 목록을 튜플로 변환 하시겠습니까?

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 유형의 기능이 있습니다. 즉, 튜플과 같은 다른 유형의 요소를 가질 수 있으며 표준 컬렉션과 같은 다른 작업간에 매핑 될 수 있습니다. 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

최대 22 개 요소의 목록을 변환하고 더 큰 목록에 대해 예외를 발생시키는 함수를 수동으로 코딩 할 수 있습니다. 곧 출시 될 기능인 Scala의 템플릿 지원은이를 더 간결하게 만들 것입니다. 그러나 이것은 추악한 해킹이 될 것입니다.