Что делать с операциями для определенного вида коллекции? - PullRequest
3 голосов
/ 30 апреля 2011

В нескольких местах моего приложения мне нужно взять Seq[SalesRow] и вернуть Map[String,SalesRow], где строка - это название страны.

Мне нужно использовать это в нескольких местах,Например, я беру список всех SalesRows и получаю глобальную разбивку продаж по странам.Но в других местах я хочу разбить свои продажи по месяцам, а затем по странам (поэтому Map[Month,Seq[SalesRow]] становится Map[Month,Map[String,Seq[SalesRow]]]) - в других местах я хочу разбить по дням, а затем по странам.

Мой вопрос: куда я помещаю (небольшое) количество логики, которая берет Seq[SalesRow] и возвращает карту стран в строках?Прямо сейчас я помещаю это в метод сопутствующего объекта, SalesRow.byCountry(rows : Seq[SalesReport].Это оптимально?

Мне пришла в голову немного более сумасшедшая идея - создать неявное преобразование из Seq[SalesRow] в EnhancedSalesRowSeq, которое имеет метод экземпляра byCountry.Это мне нравится, потому что операция применима к любой последовательности SalesRows.

Это хорошая идея?

Является ли добавление логики к объекту-компаньону моим лучшим выбором или лучшеварианты?

Спасибо.

Ответы [ 3 ]

2 голосов
/ 01 мая 2011

Если вы не знаете, библиотека поставляется с функцией groupBy.В основном, с Seq[SalesRow] он даст вам Map[T, Seq[SalesRow]] на основе функции от SalesRow до T.

Так что, если ваша функция проста, вы можете легко получить карту.Мне нравится ваша идея расширенного seq в сочетании с помещением неявного в компаньон 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))
  }
}
2 голосов
/ 30 апреля 2011

Если производительность не является вашей главной заботой, вы можете поместить логику в:

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

Так что, если неявное преобразование вы можете превратить каждый Seq в Map с членом, являющимся ключом.

1 голос
/ 01 мая 2011

Я предлагаю вам создать инкапсулирующие классы:

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

case class ContrySalesTable(rows: Seq[SalesRow])

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

Одно из преимуществ использования этого метода - одно преимущество, но другое преимущество заключается в том, что вы получите большую безопасность типов за счет простого ".rows "здесь и там.

...