Parece que Vectorfue tarde a la fiesta de las colecciones Scala, y todas las publicaciones influyentes del blog ya se habían ido.
En Java, ArrayListla colección predeterminada es la que puedo usar, LinkedListpero solo cuando he pensado en un algoritmo y me preocupo lo suficiente como para optimizarlo. En Scala, ¿debería usarlo Vectorpor defecto Seqo tratar de hacer ejercicio cuando Listsea más apropiado?
scala
vector
scala-collections
Duncan McGregor
fuente
fuente

List<String> l = new ArrayList<String>()blogs de escritura Scala para que creyera que todos usan List para obtener bondades persistentes de la colección, pero ¿Vector es lo suficientemente general como para que lo usemos en lugar de List?ListcuandoSeq()escribo en REPL.IndexedSeq.Seqes de más de tres años. A partir de Scala 2.11.4 (y anteriores), el tipo concreto predeterminado deSeqesList.Respuestas:
Como regla general, uso predeterminado
Vector. Es más rápido queListpara casi todo y más eficiente en memoria para secuencias de mayor tamaño que trivial. Consulte esta documentación del rendimiento relativo de Vector en comparación con las otras colecciones. Hay algunas desventajas para ir conVector. Específicamente:List(aunque no tanto como se podría pensar)Otro inconveniente antes de Scala 2.10 era que el soporte de coincidencia de patrones era mejor para
List, pero esto se rectificó en 2.10 con generalizados+:y:+extractores.También hay una forma más abstracta y algebraica de abordar esta pregunta: ¿qué tipo de secuencia tiene conceptualmente ? Además, que eres haciendo conceptualmente con él? Si veo una función que devuelve un
Option[A], sé que esa función tiene algunos agujeros en su dominio (y por lo tanto es parcial). Podemos aplicar esta misma lógica a las colecciones.Si tengo una secuencia de tipo
List[A], estoy afirmando efectivamente dos cosas. Primero, mi algoritmo (y datos) está completamente estructurado en pila. En segundo lugar, estoy afirmando que lo único que voy a hacer con esta colección son los recorridos completos, O (n). Estos dos realmente van de la mano. Por el contrario, si tengo algo de tipoVector[A], lo único que estoy afirmando es que mis datos tienen un orden bien definido y una longitud finita. Por lo tanto, las afirmaciones son más débilesVectory esto conduce a una mayor flexibilidad.fuente
case head +: tailocase tail :+ head. Para hacer coincidir contra vacío, puede hacercase Seq()y así sucesivamente. Todo lo que necesita está allí en la API, que es más versátil que la deList's'Listse implementa con una lista vinculada individualmente.VectorSe implementa algo como el de JavaArrayList.Bueno, a
Listpuede ser increíblemente rápido si el algoritmo se puede implementar únicamente con::,headytail. Tuve una lección objetiva de eso muy recientemente, cuando vencí a Javasplital generar un enListlugar de unArray, y no pude superar eso con nada más.Sin embargo,
Listtiene un problema fundamental: no funciona con algoritmos paralelos. No puedo dividir unListen múltiples segmentos, o volver a concatenarlo de manera eficiente.Hay otros tipos de colecciones que pueden manejar el paralelismo mucho mejor, y
Vectores una de ellas.Vectortambién tiene una gran localidad, queListno lo es, lo que puede ser una verdadera ventaja para algunos algoritmos.Entonces, teniendo en cuenta todo,
Vectores la mejor opción a menos que tenga consideraciones específicas que hagan preferible una de las otras colecciones; por ejemplo, puede elegirStreamsi desea una evaluación y almacenamiento en caché diferidos (Iteratores más rápido pero no almacena en caché), oListsi El algoritmo se implementa naturalmente con las operaciones que mencioné.Por cierto, es preferible usar
SeqoIndexedSeqmenos que desee una parte específica de la API (por ejemplo,List's::), o inclusoGenSeqoGenIndexedSeqsi su algoritmo se puede ejecutar en paralelo.fuente
Vectorhay una estructura de datos inmutable en Scala?Algunas de las declaraciones aquí son confusas o incluso incorrectas, especialmente la idea de que inmutable. Vector en Scala es algo así como una ArrayList. List y Vector son estructuras de datos inmutables y persistentes (es decir, "baratas para obtener una copia modificada"). No existe una opción predeterminada razonable, ya que podría ser para estructuras de datos mutables, sino que depende de lo que esté haciendo su algoritmo. La lista es una lista enlazada individualmente, mientras que Vector es un número entero de base 32, es decir, es una especie de árbol de búsqueda con nodos de grado 32. Usando esta estructura, Vector puede proporcionar las operaciones más comunes razonablemente rápidas, es decir, en O (log_32 ( norte)). Eso funciona para anteponer, agregar, actualizar, acceso aleatorio, descomposición en cabeza / cola. La iteración en orden secuencial es lineal. La lista, por otro lado, solo proporciona iteración lineal y anteposición de tiempo constante, descomposición en cabeza / cola.
Esto podría parecer como si Vector fuera un buen reemplazo para List en casi todos los casos, pero anteponer, la descomposición y la iteración son a menudo las operaciones cruciales en secuencias en un programa funcional, y las constantes de estas operaciones son (mucho) más altas para el vector debido a su estructura más complicada. Hice algunas mediciones, por lo que la iteración es aproximadamente el doble de rápida para la lista, el antecedente es aproximadamente 100 veces más rápido en las listas, la descomposición en la cabeza / cola es aproximadamente 10 veces más rápida en las listas y la generación de un transitable es aproximadamente 2 veces más rápida para los vectores. (Esto probablemente se deba a que Vector puede asignar matrices de 32 elementos a la vez cuando lo construye usando un generador en lugar de agregar o agregar elementos uno por uno).
Entonces, ¿qué estructura de datos debemos usar? Básicamente, hay cuatro casos comunes:
fuente
Para colecciones inmutables, si desea una secuencia, su decisión principal es si usar una
IndexedSeqo unaLinearSeq, lo que ofrece diferentes garantías de rendimiento. IndexedSeq proporciona acceso aleatorio rápido de elementos y una operación de longitud rápida. Un LinearSeq proporciona acceso rápido solo al primer elemento a través dehead, pero también tiene un acceso rápidotailoperación . (Tomado de la documentación Seq.)Para un
IndexedSeq, normalmente elegirías aVector.Ranges yWrappedStrings son también IndexedSeqs.Para un
LinearSeq, normalmente elegiría unListo su equivalente perezosoStream. Otros ejemplos sonQueuesyStacks.Entonces, en términos de Java, se
ArrayListusa de manera similar a la de ScalaVectory deLinkedListmanera similar a la de ScalaList. Pero en Scala, tendería a usar List con más frecuencia que Vector, porque Scala tiene mucho mejor soporte para funciones que incluyen el recorrido de la secuencia, como mapeo, plegado, iteración, etc. Tiende a usar estas funciones para manipular la lista como completo, en lugar de acceder aleatoriamente a elementos individuales.fuente
Vectorde que la iteración es más rápida, pero alguien necesita compararla para asegurarse.VectorExisten físicamente juntos en la RAM en grupos de 32, que se ajustan más completamente en la memoria caché de la CPU ... por lo que hay menos pérdida de memoria cachéEn situaciones que implican mucho acceso aleatorio y mutación aleatoria, a
Vector(o, como dicen los documentos , aSeq) parece ser un buen compromiso. Esto también es lo que sugieren las características de rendimiento .Además, la
Vectorclase parece funcionar bien en entornos distribuidos sin mucha duplicación de datos porque no hay necesidad de hacer una copia en escritura para el objeto completo. (Ver: http://akka.io/docs/akka/1.1.3/scala/stm.html#persistent-datastructures )fuente
IndexedSeq. Lo cual también esVector, pero ese es otro asunto.IndexedSeqque implementaSeq.Seq(1, 2, 3)es unLinearSeqque se implementa usandoList.Si está programando de manera inmutable y necesita acceso aleatorio, Seq es el camino a seguir (a menos que desee un Set, que a menudo lo hace). De lo contrario, List funciona bien, excepto que sus operaciones no pueden ser paralelas.
Si no necesita estructuras de datos inmutables, quédese con ArrayBuffer ya que es el equivalente de Scala a ArrayList.
fuente