Domanda

In diversi luoghi della mia applicazione, devo prendere un Seq[SalesRow] e restituire a Map[String,SalesRow], dove la stringa è il nome di un paese.

Devo usarlo in diversi luoghi. Ad esempio, prendo un elenco di tutti i venditori e ottengo una ripartizione globale delle vendite per paese. Ma in altri luoghi, voglio abbattere le mie vendite entro il mese e poi per paese (quindi Map[Month,Seq[SalesRow]] diventa Map[Month,Map[String,Seq[SalesRow]]]) - In altri luoghi, voglio crollare di giorno e poi per paese.

La mia domanda è: dove devo mettere la (piccola) quantità di logica che prende a Seq[SalesRow] e restituisce una mappa dei paesi alle righe? In questo momento, lo sto mettendo in un metodo oggetto di accompagnamento, SalesRow.byCountry(rows : Seq[SalesReport]. È ottimale?

Mi è venuta in mente un'idea leggermente più folle, che è quella di creare una conversione implicita da Seq[SalesRow] a EnhancedSalesRowSeq, che ha a byCountry Metodo di istanza. Questo mi piace, perché l'operazione è applicabile a qualsiasi sequenza di venditori.

E 'questa una buona idea?

L'aggiunta della logica all'oggetto compagno è la mia scelta migliore o ci sono opzioni migliori?

Grazie.

È stato utile?

Soluzione

Nel caso in cui non siate consapevole della biblioteca viene fornita con un groupBy funzione. Fondamentalmente dato a Seq[SalesRow] Ti darà un Map[T, Seq[SalesRow]] basato su una funzione da SalesRow a T.

Quindi, se la tua funzione è facile, puoi facilmente ottenere una mappa. Mi piace la tua idea della seq migliorata in combinazione con il mettere l'implicito nel SalesRow compagno:

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))
  }
}

Altri suggerimenti

Se le prestazioni non sono la tua principale preoccupazione, puoi mettere la logica a:

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

Quindi, se una conversione implicita puoi girare ogni Seq in un Map con un membro che è la chiave.

Ti suggerisco di fare classi incapsulanti:

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

case class ContrySalesTable(rows: Seq[SalesRow])

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

Avere un posto per mettere il metodo è un vantaggio, ma un altro vantaggio è che avrai una maggiore sicurezza di tipo a costo di un semplice ".rows" qui e li.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top