lists create crear list scala concatenation

create - fill list scala



Scala list concatenation,::: vs++ (4)

¿Hay alguna diferencia entre ::: y ++ para concatenar listas en Scala?

scala> List(1,2,3) ++ List(4,5) res0: List[Int] = List(1, 2, 3, 4, 5) scala> List(1,2,3) ::: List(4,5) res1: List[Int] = List(1, 2, 3, 4, 5) scala> res0 == res1 res2: Boolean = true

En la documentación parece que ++ es más general mientras que ::: es List -specific. ¿Se proporciona este último porque se usa en otros lenguajes funcionales?


Legado. La lista se definió originalmente para que fuera de un lenguaje funcional:

1 :: 2 :: Nil // a list list1 ::: list2 // concatenation of two lists list match { case head :: tail => "non-empty" case Nil => "empty" }

Por supuesto, Scala desarrolló otras colecciones, de una manera ad hoc. Cuando salió 2.8, las colecciones se rediseñaron para una máxima reutilización de código y una API consistente, de modo que pueda usar ++ para concatenar dos colecciones, e incluso iteradores. Lista, sin embargo, consiguió conservar sus operadores originales, aparte de uno o dos que quedaron en desuso.


Siempre use ::: . Hay dos razones: eficiencia y seguridad de tipo.

Eficiencia

x ::: y ::: z es más rápido que x ++ y ++ z , porque ::: es asociativo correcto. x ::: y ::: z se analiza como x ::: (y ::: z) , que es algorítmicamente más rápido que (x ::: y) ::: z (este último requiere O (| x |) más pasos).

Tipo de seguridad

Con ::: solo puedes concatenar dos List s. Con ++ puedes agregar cualquier colección a la List , lo cual es terrible:

scala> List(1, 2, 3) ++ "ab" res0: List[AnyVal] = List(1, 2, 3, a, b)

++ también es fácil mezclarse con + :

scala> List(1, 2, 3) + "ab" res1: String = List(1, 2, 3)ab


Un punto diferente es que la primera oración se analiza como:

scala> List(1,2,3).++(List(4,5)) res0: List[Int] = List(1, 2, 3, 4, 5)

Mientras que el segundo ejemplo se analiza como:

scala> List(4,5).:::(List(1,2,3)) res1: List[Int] = List(1, 2, 3, 4, 5)

Así que si estás usando macros, debes tener cuidado.

Además, ++ para dos listas está llamando a ::: pero con más sobrecarga porque solicita un valor implícito para tener un constructor de Lista a Lista. Pero los microbenchmarks no demostraron nada útil en ese sentido, supongo que el compilador optimiza tales llamadas.

Micro-Benchmarks después de calentar.

scala>def time(a: => Unit): Long = { val t = System.currentTimeMillis; a; System.currentTimeMillis - t} scala>def average(a: () => Long) = (for(i<-1 to 100) yield a()).sum/100 scala>average (() => time { (List[Int]() /: (1 to 1000)) { case (l, e) => l ++ List(e) } }) res1: Long = 46 scala>average (() => time { (List[Int]() /: (1 to 1000)) { case (l, e) => l ::: List(e ) } }) res2: Long = 46

Como dijo Daniel C. Sobrai, puede agregar el contenido de cualquier colección a una lista usando ++ , mientras que con ::: solo puede concatenar listas.


::: funciona solo con listas, mientras que ++ se puede usar con cualquier atravesable. En la implementación actual (2.9.0), ++ recurre a ::: si el argumento también es una List .