Scala: ¿cuál es la mejor manera de agregar un elemento a una matriz?

111

Di que tengo un me Array[Int]gusta

val array = Array( 1, 2, 3 )

Ahora me gustaría agregar un elemento a la matriz, decir el valor 4, como en el siguiente ejemplo:

val array2 = array + 4     // will not compile

Por supuesto, puedo usar System.arraycopy()y hacer esto por mi cuenta, pero debe haber una función de biblioteca Scala para esto, que simplemente no pude encontrar. ¡Gracias por los consejos!

Notas:

  1. Soy consciente de que puedo agregar otra matriz de elementos, como en la siguiente línea, pero eso parece demasiado indirecto:

    val array2b = array ++ Array( 4 )     // this works
  2. Soy consciente de las ventajas y desventajas de List vs Array y aquí estoy por varias razones específicamente interesado en extender un Array.

Editar 1

Gracias por las respuestas que apuntan al :+método del operador. Esto es lo que estaba buscando. Desafortunadamente, es bastante más lento que la implementación del método append () personalizado arraycopy, aproximadamente dos o tres veces más lento. Al observar la implementación en SeqLike[], se crea un constructor, luego se le agrega la matriz, luego se realiza la adición a través del constructor y luego se renderiza el constructor. No es una buena implementación para matrices. Hice un punto de referencia rápido comparando los dos métodos, mirando el tiempo más rápido de diez ciclos. Hacer 10 millones de repeticiones de un anexo de un solo elemento a una instancia de matriz de 8 elementos de alguna clase Footoma 3.1 segundos :+y 1.7 segundos con un append()método simple que usaSystem.arraycopy();hacer 10 millones de repeticiones de adición de un solo elemento en matrices de 8 elementos de Long toma 2,1 segundos :+y 0,78 segundos con el append()método simple . Me pregunto si esto no se podría arreglar en la biblioteca con una implementación personalizada para Array.

Editar 2

Por lo que vale, presenté un ticket: https://issues.scala-lang.org/browse/SI-5017

Gregor Scheidt
fuente
11
¿Por qué no utilizar ArrayBuffery su +=método? Eso le dará un anexo O (1) amortizado.
Fred Foo
1
En scala, System.arraycopy(...)se reemplaza porArray.copy(...)
paradigmático
1
¿Conoce las ventajas y desventajas de List vs Array, pero le sorprenden los resultados de referencia de 10 millones de agregados?
usuario desconocido
¿Puede ejecutar nuevamente su punto de referencia usando un ArrayBufferque se convierte después del último agregado a una matriz (con toArray)?
paradigmático
@paradigmatic: El punto de referencia, por supuesto, no fue de 10 millones de anexos a la misma matriz, sino de 10 millones de repeticiones de un solo elemento anexado a una matriz de 8 elementos. Actualicé la pregunta en consecuencia.
Gregor Scheidt

Respuestas:

204

Puede usar :+para agregar un elemento a la matriz y +:anteponerlo:

0 +: array :+ 4

debe producir:

res3: Array[Int] = Array(0, 1, 2, 3, 4)

Es lo mismo que con cualquier otra implementación de Seq.

tenshi
fuente
3
Es lo mismo para cualquier otra colección ordenada de Scala , no funciona con set, por ejemplo (ya que anteponer y añadir no significa nada para un Set).
Nicolas
@Nicolas Cualquier secuencia. Ordenar implica ordenar .
Daniel C. Sobral
@Daniel Sí, acabo de tener un pequeño agujero en la memoria cuando escribí el comentario y no encontré la palabra obvia "secuencia"
Nicolas
@tenshi ¿Todos estos operadores crearían una nueva matriz? Sí, lo hace (de: + código)Array.copy(repr, 0, result, 0, repr.length)
Timofey
59
val array2 = array :+ 4
//Array(1, 2, 3, 4)

Funciona también "invertida":

val array2 = 4 +: array
Array(4, 1, 2, 3)

También hay una versión "in situ":

var array = Array( 1, 2, 3 )
array +:= 4
//Array(4, 1, 2, 3)
array :+= 0
//Array(4, 1, 2, 3, 0)
Landei
fuente
11
Me pregunto por qué la colección Array no usa el método append (), al igual que ArrayBuffer. En mi opinión, es más Coordinar y unificar que usar un nuevo operador: + / +:
Djvu
8

El más fácil podría ser:

Array(1, 2, 3) :+ 4

En realidad, Array se puede transformar implícitamente en un WrappedArray

Nicolas
fuente
En ese caso, esa sería la conversión de mayor prioridad a ArrayOps
Didier Dupont