рд╕реНрдХрд╛рд▓рд╛ рдореЗрдВ рдЫрдВрдЯрдиреА - рдмрд┐рд▓реНрд▓рд┐рдпреЛрдВ рдкрд░ рдПрдХ рдЙрджрд╛рд╣рд░рдг

рд╣реЗрд▓реЛ, рд╣реЗрдмреНрд░! рдореИрдВ рдЖрдкрдХреЗ рджрд░рдмрд╛рд░ рдореЗрдВ рдореАрдбрд┐рдпрдо рдкрд░ рдореЗрд░реЗ рд▓реЗрдЦ рдХрд╛ рд░реВрд╕реА рдЕрдиреБрд╡рд╛рдж рд▓рд╛рддрд╛ рд╣реВрдВ: рд╕реНрдХреИрд▓рд╛ рдореЗрдВ рдЫрдВрдЯрдиреА - рдПрдХ рдмрд┐рд▓реНрд▓реА рдХреА рджреБрдХрд╛рди рдХрд╛ рдЙрджрд╛рд╣рд░рдг ред рдпрд╣ рд▓реЗрдЦ рдЙрди рдкрд╛рдардХреЛрдВ рдХреЗ рд▓рд┐рдП рд╣реИ рдЬреЛ рд╕реНрдХрд╛рд▓рд╛ рднрд╛рд╖рд╛ рдХреЗ рд╡рд╛рдХреНрдп-рд╡рд┐рдиреНрдпрд╛рд╕ рдХреЛ рдЬрд╛рдирддреЗ рд╣реИрдВ рдФрд░ рдорд╛рдирдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рдмреБрдирд┐рдпрд╛рджреА рдЙрдкрдХрд░рдгреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░ рд╣реИрдВред


рдЗрд╕ рддрдереНрдп рдХреЗ рдмрд╛рд╡рдЬреВрдж рдХрд┐ рдЬрд╛рд╡рд╛ рдФрд░ рд╕реНрдХрд╛рд▓рд╛ рджреЛрдиреЛрдВ рдЬреЗрд╡реАрдПрдо рдХреЛ рдПрдХ рд░рдирдЯрд╛рдЗрдо рдкреНрд▓реЗрдЯрдлреЙрд░реНрдо рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рд╕реНрдХрд╛рд▓рд╛ рдиреЗ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдЕрд╡рдзрд╛рд░рдгрд╛рдУрдВ рдФрд░ рдПрдХ рд╕рдореГрджреНрдз рдорд╛рдирдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдЕрдиреБрдХреВрд▓рди рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЕрдзрд┐рдХ рдЕрднрд┐рд╡реНрдпрдВрдЬрдХ рднрд╛рд╖рд╛ рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рд╕рд┐рджреНрдзрд┐ рдкреНрд░рд╛рдкреНрдд рдХреА рд╣реИред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рдЗрд╕ рдЕрднрд┐рд╡реНрдпрдВрдЬрдирд╛ рдХреЗ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реВрдВрдЧрд╛, рдпрд╣ рдХрд▓реНрдкрдирд╛ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реВрдВрдЧрд╛ рдХрд┐ рдХреЛрдб рдЖрдзрд╛рд░ рдХрд╛ рдПрдХ рдЫреЛрдЯрд╛ рд╕рд╛ рд╣рд┐рд╕реНрд╕рд╛ рдФрд░ рдЗрд╕реА рдЖрд╡рд╢реНрдпрдХрддрд╛рдПрдВ рд╕рдордп рдХреЗ рд╕рд╛рде рдХреИрд╕реЗ рд╡рд┐рдХрд╕рд┐рдд рд╣реЛ рд╕рдХрддреА рд╣реИрдВред


рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рд╡рд┐рд╡рд░рдг


рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╣рдорд╛рд░реЗ рдирд┐рдкрдЯрд╛рди рдореЗрдВ рдПрдХ рдмрд┐рд▓реНрд▓реА рдХреА рджреБрдХрд╛рди рд╣реИ (рдХреНрдпреЛрдВрдХрд┐ рдмрд┐рд▓реНрд▓рд┐рдпрд╛рдБ рд╕реНрдХрд╛рд▓рд╛ рдкрд╛рд░рд┐рд╕реНрдерд┐рддрд┐рдХреА рддрдВрддреНрд░ рдореЗрдВ рд╕рдмрд╕реЗ рд▓реЛрдХрдкреНрд░рд┐рдп рдЬрд╛рдирд╡рд░ рд╣реИрдВ)ред рдмрд┐рдХреНрд░реА рдХреЗ рд▓рд┐рдП рдЙрдкрд▓рдмреНрдз рдмрд┐рд▓реНрд▓рд┐рдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЦрд╝рд╛рд╕рд┐рдпрдд рдХреЗ рдХрд╛рд░рдг, рдХреБрдЫ рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдирд╣реАрдВ рдЖрддреА рд╣реИ рдФрд░ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ HTTP рдкреНрд░рддрд┐рд╕рд╛рдж рднреЗрдЬрдиреЗ рдпрд╛ рдХрд┐рд╕реА рдЕрдиреНрдп рддрд░реАрдХреЗ рд╕реЗ рдЗрд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЗрд╕реЗ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рд╕реЙрд░реНрдЯ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рд╡рд┐рд╖рдп рдХреНрд╖реЗрддреНрд░ рдХрд╛ рдореБрдЦреНрдп рдЙрджреНрджреЗрд╢реНрдп, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рд╣реИ, CatрдЬрд┐рд╕рдореЗрдВ рд╢реБрд░реБрдЖрдд рдореЗрдВ рдХреЗрд╡рд▓ рддреАрди рдкреНрд░рдХрд╛рд░ рдХреЗ рдЖрджрд┐рдо рдкреНрд░рдХрд╛рд░ рд╣реИрдВред рд▓рдХреНрд╖реНрдп рдирд┐рдореНрди рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдмрд┐рд▓реНрд▓реА рд╕рдВрдЧреНрд░рд╣ рдХреЛ рдЫрд╛рдБрдЯрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдПрдкреАрдЖрдИ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдирд╛ рд╣реИ:


  • рдкреНрд░рддреНрдпреЗрдХ рдлрд╝реАрд▓реНрдб рдХреЗ рд▓рд┐рдП рдХреНрд░рдордмрджреНрдз рдХреНрд░рдо рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
  • рдХрд┐рд╕реА рднреА рдлрд╝реАрд▓реНрдб рдХреЗ рд▓рд┐рдП рдХреНрд░рдордмрджреНрдз рдХреНрд░рдо рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ
  • рд╕реЙрд░реНрдЯ рдПрдХ рдЕрдкрд░рд┐рднрд╛рд╖рд┐рдд рд╕реЙрд░реНрдЯ рдХреНрд░рдо рд╡рд╛рд▓реЗ рдлрд╝реАрд▓реНрдб рдХреЗ рд▓рд┐рдП рд╕реНрдерд┐рд░ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП
  • рдкреНрд░рддреНрдпреЗрдХ рдлрд╝реАрд▓реНрдб рдХреА рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рддрдм рд╣реЛрддреА рд╣реИ рдЬрдм рдЫрдБрдЯрд╛рдИ (рдпрд╛рдиреА рдлрд╝реАрд▓реНрдб рджреНрд╡рд╛рд░рд╛ рдЫрдБрдЯрд╛рдИ ageрдХрд░рдирд╛ рд╣рдореЗрд╢рд╛ рдХреНрд╖реЗрддреНрд░ рджреНрд╡рд╛рд░рд╛ рдЫрдБрдЯрд╛рдИ рдХрд░рдиреЗ рд╕реЗ рдЕрдзрд┐рдХ рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рд╣реЛрдЧреА name)

рдкрд╣рд▓рд╛ рдкреБрдирд░рд╛рд╡реГрддрд┐


case class Cat(age: Int,
               name: String,
               available: Boolean)

рдЪреВрдВрдХрд┐ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдмрдпрд╛рди рдЕрдкреЗрдХреНрд╖рд╛рдХреГрдд рд╕рд░рд▓ рд╣реИ рдФрд░ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рдЕрдиреНрдп рд╣рд┐рд╕реНрд╕реЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреЛрдИ рдЬрд╛рдирдХрд╛рд░реА рдирд╣реАрдВ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдкреНрд░рд╛рд░рдВрднрд┐рдХ рд╕рдорд╛рдзрд╛рди рдХреЛ рд╕рд░рд▓ рдмрдирд╛рдирд╛ рдмреЗрд╣рддрд░ рд╣реИред рд╕реМрднрд╛рдЧреНрдп рд╕реЗ, рдпрд╣ scala.Orderingрдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдПрдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╡рд┐рдзрд┐ Tuple3рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕рдХреЗ рд╕рд╛рде рдЖрдк OrderingрдЖрдпрд╛рдо 3 рдХреЗ рдЯреНрдпреВрдкрд▓реНрд╕ рдХреЗ рд▓рд┐рдП рдЙрджрд╛рд╣рд░рдг рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ , рдЬрд┐рд╕рд╕реЗ рдХрдХреНрд╖рд╛ рдХреА рдХреЛрдИ рднреА рд╡рд╕реНрддреБ рдЖрд╕рд╛рдиреА рд╕реЗ рдХрдо рд╣реЛ рдЬрд╛рддреА рд╣реИ Catред


, Tuple3 , . , тАФ Tuple1, Tuple2, Tuple3, Ordering, . 9 (3 3 ), .


, API , " " . , 3 : (), ( ) "" ( ). (ADT):


sealed trait SortOrder

object SortOrder {

  case object Keep extends SortOrder

  case object Asc extends SortOrder

  case object Desc extends SortOrder
}

Ordering. SortOrder , , , :


import common.OrderingUtil
import iteration1.SortOrder.{Asc, Desc, Keep}

object syntax {

  implicit class OrderSyntax(val order: SortOrder) extends AnyVal {

    def apply[A](ordering: Ordering[A]): Ordering[A] =
      order match {
        case Keep => OrderingUtil.identity
        case Asc => ordering
        case Desc => ordering.reverse
      }
  }
}

OrderingUtil.identity тАФ , A, . : Ordering.by(_ => 0).


, , Ordering[Cat]. CatOrdering:


import iteration1.syntax._

object CatOrdering {

  def of(idOrder: SortOrder,
         nameOrder: SortOrder,
         availableOrder: SortOrder): Ordering[Cat] =
    Ordering
      .Tuple3(idOrder(Ordering.Int), nameOrder(Ordering.String), availableOrder(Ordering.Boolean))
      .on[Cat](cat => (cat.age, cat.name, cat.available))
}

(Ordering[Cat]) CatOrdering.of:


CatOrdering.of(SortOrder.Asc, SortOrder.Keep, SortOrder.Desc)

, ScalaTest ScalaCheck property-based . , . .



Cat .


case class Cat(age: Int,
               name: String,
               available: Boolean,
               owner: Option[String])

, тАФ ( null!), , , , . , 4 :


  1. , ()
  2. ,
  3. ,
  4. , ( )

(1 4) scala.Ordering.Option, 2 . SortOrder , :


sealed trait SortOrder

object SortOrder {

  case class Asc(emptyFirst: Boolean) extends SortOrder

  case class Desc(emptyFirst: Boolean) extends SortOrder

  case object Keep extends SortOrder

  object Asc {
    def emptyFirst: Asc = Asc(emptyFirst = true)

    def emptyLast: Asc = Asc(emptyFirst = false)
  }

  object Desc {
    def emptyFirst: Desc = Desc(emptyFirst = true)

    def emptyLast: Desc = Desc(emptyFirst = false)
  }
}

SortOrder. optional Ordering[Option[A]] A, , SortOrder. , , Ordering[Option[A]] apply, Ordering[Option[A]], . , A apply Option. <:<, StackOverflow ( Dotty Not ).


import common.OrderingUtil
import iteration2.sort_order.SortOrder._

object syntax {

  private object OptionOrdering {

    def apply[A](rootOrdering: Ordering[A],
                 emptyFirst: Boolean): Ordering[Option[A]] =
      if (emptyFirst)
        OptionOrdering.emptyFirst(rootOrdering)
      else
        OptionOrdering.emptyLast(rootOrdering)

    def emptyFirst[A](rootOrdering: Ordering[A]): Ordering[Option[A]] =
      (x: Option[A], y: Option[A]) => (x, y) match {
        case (None, None) => 0
        case (None, _) => -1
        case (_, None) => 1
        case (Some(a), Some(b)) => rootOrdering.compare(a, b)
      }

    def emptyLast[A](rootOrdering: Ordering[A]): Ordering[Option[A]] =
      (x: Option[A], y: Option[A]) => (x, y) match {
        case (None, None) => 0
        case (None, _) => 1
        case (_, None) => -1
        case (Some(a), Some(b)) => rootOrdering.compare(a, b)
      }
  }

  implicit class OrderSyntax(val order: SortOrder) extends AnyVal {

    def optional[A](ordering: Ordering[A]): Ordering[Option[A]] =
      order match {
        case Keep => OrderingUtil.identity
        case Asc(emptyFirst) => OptionOrdering(ordering, emptyFirst)
        case Desc(emptyFirst) => OptionOrdering(ordering.reverse, emptyFirst)
      }

    def apply[A](ordering: Ordering[A]): Ordering[A] =
      order match {
        case Keep => OrderingUtil.identity
        case Asc(_) => ordering
        case Desc(_) => ordering.reverse
      }
  }
}

import iteration2.sort_order.SortOrder
import iteration2.sort_order.syntax._

import scala.Ordering.{Boolean => BooleanO, Int => IntO, String => StringO}

object CatOrdering {

  def toOrdering(idOrder: SortOrder,
                 nameOrder: SortOrder,
                 availableOrder: SortOrder,
                 ownerOrder: SortOrder): Ordering[Cat] = {
    Ordering
      .Tuple4(idOrder(IntO), nameOrder(StringO), availableOrder(BooleanO), ownerOrder.optional(StringO))
      .on[Cat](cat => (cat.age, cat.name, cat.available, cat.owner))
  }
}

Ordering[Cat] . , .


CatOrdering.toOrdering(
  SortOrder.Asc.emptyFirst, 
  SortOrder.Asc.emptyFirst, 
  SortOrder.Asc.emptyFirst,
  SortOrder.Asc.emptyFirst
)

, Option, . .



. , :


  1. .
  2. - , SortOrder.Keep.
  3. Cat 9. Tuple10 .

- . , Cat 10 . , , . , , SortOrder . .


, , . Cat. ( тДЦ1) ( тДЦ2), ( тДЦ3). (SortOrder ):


import java.time.LocalDate

case class Cat(age: Int,
               name: String,
               available: Boolean,
               owner: Option[String],
               breed: String,
               furColor: String,
               eyeColor: String,
               registrationId: String,
               lastHealthCheck: Option[LocalDate],
               urgentSell: Boolean)

import java.time.LocalDate

import iteration3.sort_order.SortOrder
import iteration3.sort_order.syntax._

import scala.Ordering._

sealed trait CatField {
  def toOrdering(sortOrder: SortOrder): Ordering[Cat]
}

object CatField {

  case object Age extends CatField {
    override def toOrdering(sortOrder: SortOrder): Ordering[Cat] =
      sortOrder(Ordering.Int).on(_.age)
  }

  case object Name extends CatField {
    override def toOrdering(sortOrder: SortOrder): Ordering[Cat] =
      sortOrder(Ordering.String).on(_.name)
  }

  case object Available extends CatField {
    override def toOrdering(sortOrder: SortOrder): Ordering[Cat] =
      sortOrder(Ordering.Boolean).on(_.available)
  }

  case object Owner extends CatField {
    override def toOrdering(sortOrder: SortOrder): Ordering[Cat] =
      sortOrder.optional(Ordering.String).on(_.owner)
  }

  case object Breed extends CatField {
    override def toOrdering(sortOrder: SortOrder): Ordering[Cat] =
      sortOrder(Ordering.String).on(_.breed)
  }

  case object FurColor extends CatField {
    override def toOrdering(sortOrder: SortOrder): Ordering[Cat] =
      sortOrder(Ordering.String).on(_.furColor)
  }

  case object EyeColor extends CatField {
    override def toOrdering(sortOrder: SortOrder): Ordering[Cat] =
      sortOrder(Ordering.String).on(_.eyeColor)
  }

  case object RegistrationId extends CatField {
    override def toOrdering(sortOrder: SortOrder): Ordering[Cat] =
      sortOrder(Ordering.String).on(_.registrationId)
  }

  case object LastHealthCheck extends CatField {
    override def toOrdering(sortOrder: SortOrder): Ordering[Cat] =
      sortOrder.optional(Ordering.by[LocalDate, Long](_.toEpochDay)).on(_.lastHealthCheck)
  }

  case object UrgentSell extends CatField {
    override def toOrdering(sortOrder: SortOrder): Ordering[Cat] =
      sortOrder(Ordering.Boolean).on(_.urgentSell)
  }
}

import common.OrderingUtil
import iteration3.sort_order.SortOrder

object CatOrdering {

  def byFields(fields: Seq[(CatField, SortOrder)]): Ordering[Cat] =
    if (fields.isEmpty) OrderingUtil.identity[Cat]
    else {
      val (head, headOrder) = fields.head
      val (res, _) = fields.tail.foldLeft[(Ordering[Cat], Set[CatField])]((head.toOrdering(headOrder), Set())) {
        case (acc@(_, presentFields), (field, _)) if presentFields.contains(field) =>
          acc

        case ((ordering, presentFields), (field, order)) =>
          (ordering.orElse(field.toOrdering(order)), presentFields + field)
      }
      res
    }
}

orElse, , . thenComparing Comparator Java. Ordering, Comparator . , orElse Scala, orElseBy.


, , byFields , . , OrderingUtil.identity, . " ", foldLeft, .


SortOrder.Keep, , , . , , . HTTP , .


. , , , . ( ) , , . , , , , , .


.



рдпрджреНрдпрдкрд┐ рдЕрдВрддрд┐рдо рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЕрдиреНрдп рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рднрд╛рд╖рд╛рдУрдВ рдореЗрдВ рд╕рдорд╛рди рджрд┐рдЦ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд╕реНрдХрд╛рд▓рд╛ рдЯрд╛рдЗрдк рд╕реБрд░рдХреНрд╖рд╛ рдФрд░ рдХреЛрдб рд╕рдордЭ рдФрд░ рдкрдардиреАрдпрддрд╛ рдХреЗ рдмреАрдЪ рдПрдХ рдЕрдЪреНрдЫрд╛ рд╕рдордЭреМрддрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдЗрд╕ рдкреНрд░рдХрд╛рд╢рди рдиреЗ рдмреЗрд╣рддрд░ рддрд░реАрдХреЗ рд╕реЗ рд╕рдордЭрдиреЗ рдореЗрдВ рдорджрдж рдХреА рдХрд┐ рдХреИрд╕реЗ рд╕реНрдХрд╛рд▓рд╛ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣ рдХреЛ рд╕реЙрд░реНрдЯ рдХрд░рдирд╛ рд╣реИ, рдпрд╛ рд╕реБрдЭрд╛рдП рдЧрдП рд╡рд┐рдЪрд╛рд░реЛрдВ рдХреЛ рдХреЛрдб рдореЗрдВ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдЬреЛ рд╕реАрдзреЗ рд╕рдВрдмрдВрдзрд┐рдд рдирд╣реАрдВ рд╣реИ Orderingред


рдЗрд╕ github рднрдВрдбрд╛рд░ рдореЗрдВ рд╕рднреА рдирдореВрдирд╛ рдХреЛрдб рдЙрдкрд▓рдмреНрдз рд╣реИрдВ ред


All Articles