3 개의 요소가있는 목록을 크기 3의 튜플로 변환하려면 어떻게해야합니까?
예를 들어, 내가 가지고 val x = List(1, 2, 3)있고 이것을 (1, 2, 3). 어떻게 할 수 있습니까?
3 개의 요소가있는 목록을 크기 3의 튜플로 변환하려면 어떻게해야합니까?
예를 들어, 내가 가지고 val x = List(1, 2, 3)있고 이것을 (1, 2, 3). 어떻게 할 수 있습니까?
x match { case a :: b :: c :: Nil => (a, b, c); case _ => (0, 0, 0) }과 같이) 결과 유형이 다음과 같이 고정되어 있음을 고려 하고 유의하십시오.Tuple3[Int,Int,Int]
List ' HList유형을 살펴볼 수 있습니다 . 사용 사례에 적용 할 수 있습니다.
답변:
형식이 안전한 방식으로는이 작업을 수행 할 수 없습니다. 왜? 일반적으로 우리는 런타임까지 목록의 길이를 알 수 없기 때문입니다. 그러나 튜플의 "길이"는 해당 유형으로 인코딩되어야하며 따라서 컴파일 타임에 알려 져야합니다. 예를 들면(1,'a',true) 에는 유형 (Int, Char, Boolean)이 Tuple3[Int, Char, Boolean]있습니다. 튜플에이 제한이있는 이유는 비 동종 유형을 처리 할 수 있어야하기 때문입니다.
case class Vec3[A](_1: A, _2: A, _3: A)
map이 작동 등
스칼라 추출기와 패턴 일치를 사용하여 수행 할 수 있습니다 ( 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)
}
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
따라서 동일한 문제가 발생하면 튜플이 필요하지 않습니다.
val List(c1, c2, c3) = myList
형식이 안전한 방식으로는이 작업을 수행 할 수 없습니다. Scala에서 목록은 어떤 유형의 요소의 임의 길이 시퀀스입니다. 유형 시스템이 아는 한x 한 임의의 길이 목록이 될 수 있습니다.
반대로, 튜플의 배열은 컴파일 타임에 알아야합니다. 할당을 허용하는 유형 시스템의 안전 보장을 위반합니다.x튜플 유형에 을 .
사실 기술적 인 이유로 스칼라 튜플 은 22 개 요소로 제한되었지만 2.11에서는 더 이상 존재하지 않습니다. 케이스 클래스 제한은 2.11에서 해제되었습니다. https://github.com/scala/scala/pull/2305
최대 22 개 요소의 목록을 변환하고 더 큰 목록에 대해 예외를 발생시키는 함수를 수동으로 코딩 할 수 있습니다. 곧 출시 될 기능인 Scala의 템플릿 지원은이를 더 간결하게 만들 것입니다. 그러나 이것은 추악한 해킹이 될 것입니다.
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)
다음을 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))
유형에 안전합니다. None튜플 크기가 올바르지 않으면 을 얻지 만 튜플 크기는 리터럴 또는 final val(로 변환 가능 shapeless.Nat) 이어야합니다 .
패턴 매칭 사용 :
val intTuple = List (1,2,3) match {case List (a, b, c) => (a, b, c)}
List/ 의 길이 Tuple가 알려진 상수 인 경우에만 적용됩니다 .
2015 년 포스트. 를 들어 톰 크로켓의 대답은 더 할 수 명확히 , 여기에 실제 예입니다.
처음에는 혼란 스러웠습니다. 저는 Python에서 왔기 때문에 tuple(list(1,2,3)).
Scala 언어가 부족합니까? (답은-Scala 나 Python이 아니라 정적 유형과 동적 유형에 관한 것입니다.)
그것이 내가 왜 스칼라가 이것을 할 수 없는지 핵심을 찾으려고하는 이유이다.
다음 코드 예제 toTuple에서는 type-safe toTupleN및 type-unsafe 가 있는 메서드 를 구현합니다 toTuple.
이 toTuple메서드는 런타임에 유형 길이 정보를 얻습니다. 즉, 컴파일 시간에 유형 길이 정보가 없으므로 반환 유형은 실제로 ProductPython과 매우 유사합니다 tuple(각 위치에 유형이없고 유형 길이가 없음).
그런 식으로 유형 불일치 또는IndexOutOfBoundException . (따라서 Python의 편리한 list-to-tuple은 공짜 점심이 아닙니다.)
반대로 toTupleN컴파일 타임을 안전하게 만드는 것은 사용자가 제공 한 길이 정보 입니다.
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!
def toTuple(x: List[Int]): RR의 유형은 무엇입니까?