Si tengo una colección c
de tipos T
y hay una propiedad p
en T
(de tipo P
, por ejemplo), ¿cuál es la mejor manera de hacer una clave de mapa por extracción ?
val c: Collection[T]
val m: Map[P, T]
Una forma es la siguiente:
m = new HashMap[P, T]
c foreach { t => m add (t.getP, t) }
Pero ahora necesito un mapa mutable . ¿Hay una mejor manera de hacer esto para que esté en 1 línea y termine con un Mapa inmutable ? (Obviamente, podría convertir lo anterior en una simple utilidad de biblioteca, como lo haría en Java, pero sospecho que en Scala no hay necesidad)
scala
map
scala-collections
oxbow_lakes
fuente
fuente
Traversable[K].mapTo( K => V)
yTraversable[V].mapBy( V => K)
fueron mejores!c
conc.iterator
para evitar la creación de una colección intermedia.Puede construir un mapa con un número variable de tuplas. Por lo tanto, use el método de mapa en la colección para convertirlo en una colección de tuplas y luego use el truco: _ * para convertir el resultado en un argumento variable.
fuente
Además de la solución de @James Iry, también es posible lograr esto usando un pliegue. Sospecho que esta solución es un poco más rápida que el método de tupla (se crean menos objetos basura):
fuente
list.foldLeft(Map[String,Int]()) { (m,s) => m + (s -> s.length) }
. Tenga en cuenta que si quieres usar una coma para construir la tupla, necesita un par adicional de paréntesis:((s, s.length))
.Esto se puede implementar de manera inmutable y con un solo recorrido al plegar la colección de la siguiente manera.
La solución funciona porque agregar a un Mapa inmutable devuelve un nuevo Mapa inmutable con la entrada adicional y este valor sirve como acumulador a través de la operación de plegado.
La desventaja aquí es la simplicidad del código versus su eficiencia. Por lo tanto, para colecciones grandes, este enfoque puede ser más adecuado que usar 2 implementaciones transversales como la aplicación
map
ytoMap
.fuente
Otra solución (puede que no funcione para todos los tipos)
esto evita la creación de la lista de intermediarios, más información aquí: Scala 2.8 breakOut
fuente
Lo que estás tratando de lograr es un poco indefinido.
¿Qué pasa si dos o más elementos
c
comparten lo mismop
? ¿Qué elemento se asignará a esop
en el mapa?La forma más precisa de ver esto es generar un mapa entre
p
y todos losc
elementos que lo tienen:Esto podría lograrse fácilmente con groupBy :
Si aún desea el mapa original, puede, por ejemplo, asignar
p
al primerot
que lo tiene:fuente
collect
lugar demap
. Por ejemplo:c.group(t => t.p) collect { case (Some(p), ts) => p -> ts.head }
. De esta forma, puede hacer cosas como aplanar mapas cuando la tecla es una Opción [_]..mapValues(_.head)
lugar del mapa.Probablemente esta no sea la forma más eficiente de convertir una lista en un mapa, pero hace que el código de llamada sea más legible. Usé conversiones implícitas para agregar un método mapBy a List:
Ejemplo de código de llamada:
Tenga en cuenta que debido a la conversión implícita, el código de la persona que llama necesita importar las conversiones implícitas de scala.
fuente
Funciona bien y es muy intuitivo.
fuente
c
como clave (más o menos). Tenga en cuenta "map" porque la colección resultante no es una escalaMap
sino que crea otra lista / iterable de tuplas ... pero el efecto es el mismo para el propósito del OP, no descartaría la simplicidad pero no es tan eficiente como lafoldLeft
solución, ni es la verdadera respuesta a la pregunta "convertir en una colección en un mapa por clave"¿Qué tal usar zip y toMap?
fuente
Por lo que vale, aquí hay dos formas inútiles de hacerlo:
fuente
Map.fromList $ map (bar &&& id) c
,Map.fromList $ map (bar >>= (,)) c
.Esto funciona para mi:
El mapa debe ser mutable y el mapa debe ser devuelto ya que agregarlo a un mapa mutable no devuelve un mapa.
fuente
val personsMap = persons.foldLeft(Map[Int, PersonDTO]()) { (m, p) => m + (p.id -> p) }
el mapa puede ser inmutable, como se evidencia anteriormente, porque al agregarlo a un mapa inmutable, se devuelve un nuevo mapa inmutable con la entrada adicional. Este valor sirve como acumulador a través de la operación de plegado.use map () en la colección seguido de toMap
fuente
Si se convierte de Json String (leyendo un archivo json) a Scala Map
fuente