Что делать с операциями для определенного вида коллекции?

StackOverflow https://stackoverflow.com/questions/5843849

  •  27-10-2019
  •  | 
  •  

Вопрос

В нескольких разных местах в моем приложении мне нужно взять 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" здесь и там.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top