tutorial funciones español list scala tuples

list - español - funciones en scala



Convierte una lista Scala en una tupla? (12)

A pesar de la simplicidad y no es para listas de cualquier longitud, es seguro y la respuesta en la mayoría de los casos:

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))

Otra posibilidad, cuando no quieres nombrar la lista ni repetirla (espero que alguien pueda mostrar una forma de evitar las partes de Seq / cabeza):

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

Editar: agregado soporte faltante

¿Cómo puedo convertir una lista con (por ejemplo) 3 elementos en una tupla de tamaño 3?

Por ejemplo, supongamos que tengo val x = List(1, 2, 3) y quiero convertir esto en (1, 2, 3) . ¿Cómo puedo hacer esto?


Esto también se puede hacer shapeless con menos repetitivo utilizando 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))

Es seguro para tipos: obtienes None , si el tamaño de la tupla es incorrecto, pero el tamaño de la tupla debe ser un valor literal o final val (para ser convertible a shapeless.Nat . shapeless.Nat ).


FWIW, quería una tupla para iniciar un número de campos y quería usar el azúcar sintáctico de la asignación de tuplas. P.EJ:

val (c1, c2, c3) = listToTuple(myList)

Resulta que también hay azúcar sintáctica para asignar los contenidos de una lista ...

val c1 :: c2 :: c3 :: Nil = myList

Así que no hay necesidad de tuplas si tienes el mismo problema.


No puedes hacer esto de forma segura. En Scala, las listas son secuencias de longitud arbitraria de elementos de algún tipo. En lo que respecta al sistema de tipos, x podría ser una lista de longitud arbitraria.

Por el contrario, la aria de una tupla debe conocerse en tiempo de compilación. Violaría las garantías de seguridad del sistema tipo para permitir la asignación de x a un tipo de tupla.

De hecho, por razones técnicas, las tuplas de Scala estaban limitadas a 22 elementos , pero el límite ya no existe en 2.11 El límite de la clase de caso se ha eliminado en 2.11 https://github.com/scala/scala/pull/2305

Sería posible codificar manualmente una función que convierta listas de hasta 22 elementos y arroje una excepción para listas más grandes. El soporte de plantillas de Scala, una función próxima, lo haría más conciso. Pero esto sería un hack feo.


No puedes hacer esto de una manera segura. ¿Por qué? Porque, en general, no podemos conocer la longitud de una lista hasta el tiempo de ejecución. Pero la "longitud" de una tupla debe codificarse en su tipo y, por lo tanto, conocerse en tiempo de compilación. Por ejemplo, (1,''a'',true) tiene el tipo (Int, Char, Boolean) , que es azúcar para Tuple3[Int, Char, Boolean] . La razón por la cual las tuplas tienen esta restricción es que necesitan poder manejar tipos no homogéneos.


Publicación de 2015 Para que la respuesta de Tom Crockett sea ​​más esclarecedora , aquí hay un ejemplo real.

Al principio, me confundí al respecto. Porque vengo de Python, donde puedes hacer tuple(list(1,2,3)) .
¿Es corto del lenguaje Scala? (La respuesta es: no se trata de Scala o Python, se trata de tipo estático y de tipo dinámico).

Eso me hace tratar de encontrar el quid por qué Scala no puede hacer esto.

El siguiente ejemplo de código implementa un método toTuple , que tiene type-safe toTupleN y type-unsafe toTuple .

El método toTuple obtiene la información de longitud de tipo en tiempo de ejecución, es decir, no hay información de longitud de tipo en tiempo de compilación, por lo que el tipo de devolución es Product que es muy similar a la tuple de Python (no hay tipo en cada posición ni longitud de tipos).
De esa forma se pronedó el error de tiempo de ejecución como type-mismatch o IndexOutOfBoundException . (por lo que la conveniente lista-a-tupla de Python no es almuerzo gratis).

Por el contrario, es la información de longitud proporcionada por el usuario lo que hace que el toTupleN compilación toTupleN sea ​​seguro.

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!


Puedes hacerlo usando scala extractors y pattern matching ( link ):

val x = List(1, 2, 3) val t = x match { case List(a, b, c) => (a, b, c) }

Lo cual devuelve una tupla

t: (Int, Int, Int) = (1,2,3)

Además, puede utilizar un operador comodín si no está seguro acerca de un tamaño de la lista

val t = x match { case List(a, b, c, _*) => (a, b, c) }


Si está seguro de que su list.size <23 lo usa:

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)


en cuanto tienes el tipo:

val x: List[Int] = List(1, 2, 3) def doSomething(a:Int *) doSomething(x:_*)


puedes hacer esto

  1. a través de la coincidencia de patrones (lo que no desea) o
  2. iterando a través de la lista y aplicando cada elemento uno por uno.

    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)]


un ejemplo usando 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

Nota: el compilador necesita algunos tipos de información para convertir la Lista en la Lista H que la razón por la que necesita pasar información de tipo al método toHList


Shapeless 2.0 cambió algo de sintaxis. Aquí está la solución actualizada que usa información.

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

El principal problema es que el tipo para .toHList debe especificarse con anticipación. En términos más generales, dado que las tuplas son limitadas en su aspecto, el diseño de su software podría estar mejor atendido por una solución diferente.

Aún así, si está creando una lista estáticamente, considere una solución como esta, también usando información. Aquí, creamos una HList directamente y el tipo está disponible en tiempo de compilación. Recuerde que una HList tiene características de los tipos List y Tuple. es decir, puede tener elementos con diferentes tipos, como una Tupla, y puede mapearse entre otras operaciones, como colecciones estándar. Los HLists tardan un poco en acostumbrarse, así que pise lentamente si es nuevo.

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)