3

在我的应用程序的几个不同地方,我需要使用 aSeq[SalesRow]并返回 a Map[String,SalesRow],其中的字符串是一个国家/地区的名称。

我需要在几个地方使用它。例如,我列出所有 SalesRows 并按国家/地区获得全球销售额细分。但在其他地方,我想按月和国家/地区细分我的销售额(这样Map[Month,Seq[SalesRow]]就变成Map[Month,Map[String,Seq[SalesRow]]]了)——在其他地方,我想按天细分,然后按国家/地区细分。

Seq[SalesRow]我的问题是:我在哪里放置需要 a并将国家地图返回到行的(少量)逻辑?现在,我将它放在伴随对象方法中,SalesRow.byCountry(rows : Seq[SalesReport]. 那是最优的吗?

我想到了一个稍微疯狂的想法,那就是创建一个从Seq[SalesRow]to的隐式转换EnhancedSalesRowSeq,它有一个byCountry实例方法。这对我很有吸引力,因为该操作适用于任何 SalesRows 序列。

这是一个好主意吗?

将逻辑添加到伴生对象是我的最佳选择,还是有更好的选择?

谢谢。

4

3 回答 3

2

如果性能不是您主要关心的问题,您可以将逻辑放在:

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

因此,如果是隐式转换,您可以将 each 转换Seq为 a Map,其中成员为键。

于 2011-04-30T19:29:20.913 回答
2

如果您不知道该库带有一个groupBy功能。基本上给定 aSeq[SalesRow]它会给你一个Map[T, Seq[SalesRow]]基于从SalesRowto的函数T

因此,如果您的功能很简单,您可以轻松获得地图。我确实喜欢您对增强序列的想法以及将隐含在SalesRow同伴中的想法:

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))
  }
}
于 2011-05-01T02:26:24.630 回答
1

我建议你做封装类:

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

case class ContrySalesTable(rows: Seq[SalesRow])

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

有一个地方放置该方法是一个好处,但另一个好处是您将获得更大的类型安全性,但代价是.rows这里和那里的简单“”。

于 2011-05-01T02:46:34.607 回答