Pregunta

En varios lugares diferentes de mi aplicación, necesito tomar un Seq[SalesRow] y devolver un Map[String,SalesRow], donde la cadena es el nombre de un país.

Necesito usar esto en varios lugares. Por ejemplo, tomo una lista de todas las sesions y obtengo un desglose global de las ventas por país. Pero en otros lugares, quiero desglosar mis ventas por mes y luego por país (así que Map[Month,Seq[SalesRow]] convertirse en Map[Month,Map[String,Seq[SalesRow]]]) - En otros lugares, quiero romper por día y luego en país.

Mi pregunta es: ¿dónde pongo la (pequeña) cantidad de lógica que toma una Seq[SalesRow] ¿Y devuelve un mapa de países a las filas? En este momento, lo estoy poniendo en un método de objeto complementario, SalesRow.byCountry(rows : Seq[SalesReport]. ¿Eso es óptimo?

Se me ocurrió una idea un poco más loca, que es crear una conversión implícita de Seq[SalesRow] a EnhancedSalesRowSeq, que tiene un byCountry Método de instancia. Esto me atrae, porque la operación es aplicable a cualquier secuencia de vajeros.

¿Es esta una buena idea?

¿Agregar la lógica al objeto complementario es mi mejor opción o hay mejores opciones?

Gracias.

¿Fue útil?

Solución

En caso de que no sepa, la biblioteca viene con un groupBy función. Básicamente dado un Seq[SalesRow] te dará un Map[T, Seq[SalesRow]] basado en una función de SalesRow a T.

Entonces, si su función es fácil, puede obtener fácilmente un mapa. Me gusta tu idea del SEQ mejorado junto con poner lo implícito en el SalesRow compañero:

case class SalesRow(val month:Int, val country:String, 
  val person:String, val amount:Float)

class EnhancedRow(rows: Seq[SalesRow]) {
  def byCountry: Map[String, Seq[SalesRow]] = 
    rows.groupBy(_.country)
  def byMonth: Map[Int, Seq[SalesRow]] = 
    rows.groupBy(_.month)
  def byCountryByMonth: Map[String, Map[Int, Seq[SalesRow]]] = byCountry.mapValues(r => new EnhancedRow(rows).byMonth)
}

object SalesRow {
  implicit def toEnhanced(rows: Seq[SalesRow]) = new EnhancedRow(rows) 
}

object Test {
  def main(args:Array[String] = null) {
    val seq: Seq[SalesRow] = // ... fill this
    println(seq.byCountry)
    println(seq.byCountryByMonth)
    // same as:
    println(seq.byCountry.mapValues(_.byMonth))
  }
}

Otros consejos

Si el rendimiento no es su principal preocupación, puede poner la lógica en:

class RichTraversable[A](t: Traversable[A]) {
  def toMapBy[B](f: A => B): Map[B,A] = t.map{ e => (f(e),e) }.toMap
}

Entonces, si una conversión implícita, puede girar cada Seq en un Map con un miembro siendo la clave.

Te sugiero que hagas clases de encapsulación:

case class AllSalesTable(rows: Seq[SalesRow]) {
  def toSalesByCountry: SalesByCountry
}

case class ContrySalesTable(rows: Seq[SalesRow])

case class SalesByCountry(map: Map[String, CountrySalesTable])

Tener un lugar para poner el método es un beneficio, pero otro beneficio es que tendrá una mayor seguridad de tipo a costa de un simple ".rows" aquí y allá.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top