Что делать с операциями для определенного вида коллекции?
Вопрос
В нескольких разных местах в моем приложении мне нужно взять Seq[SalesRow]
и вернуть а Map[String,SalesRow]
, где строка является названием страны.
Мне нужно использовать это в нескольких местах. Например, я беру список всех продаж и получаю глобальную разбивку продаж по стране. Но в других местах я хочу разбить свои продажи по месяцу, а затем по стране (так что Map[Month,Seq[SalesRow]]
становится Map[Month,Map[String,Seq[SalesRow]]]
) - В других местах я хочу сломаться днем, а затем по стране.
Мой вопрос: куда мне поместить (небольшое) количество логики, которая берет Seq[SalesRow]
и возвращает карту стран в ряды? Прямо сейчас я помещаю это в метод компаньона, SalesRow.byCountry(rows : Seq[SalesReport]
. Анкет Это оптимально?
Мне пришла в голову немного безумная идея, которая заключается в том, чтобы создать неявное преобразование от Seq[SalesRow]
к EnhancedSalesRowSeq
, который имеет byCountry
Метод экземпляра. Это мне нравится, потому что операция применима к любой последовательности продаж.
Это хорошая идея?
Является ли добавление логики в компаньон, мой лучший выбор, или есть лучшие варианты?
Спасибо.
Решение
Если вы не знаете, библиотека поставляется с 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))
}
}
Другие советы
Если производительность не является вашей главной проблемой, вы можете поставить логику на:
class RichTraversable[A](t: Traversable[A]) {
def toMapBy[B](f: A => B): Map[B,A] = t.map{ e => (f(e),e) }.toMap
}
Так что, если неявное преобразование, вы можете повернуть каждое Seq
в а Map
с участником, являющимся ключом.
Я предлагаю вам сделать инкапсулирующие занятия:
case class AllSalesTable(rows: Seq[SalesRow]) {
def toSalesByCountry: SalesByCountry
}
case class ContrySalesTable(rows: Seq[SalesRow])
case class SalesByCountry(map: Map[String, CountrySalesTable])
Иметь где -то место для того, чтобы поместить метод, это одно преимущество, но еще одно преимущество заключается в том, что у вас будет более высокая безопасность типа за счет простого ».rows
" здесь и там.