рд╣реЗрд▓реЛ, рд╣реЗрдмреНрд░! рдореИрдВ рдЖрдкрдХреЗ рджрд░рдмрд╛рд░ рдореЗрдВ рдореАрдбрд┐рдпрдо рдкрд░ рдореЗрд░реЗ рд▓реЗрдЦ рдХрд╛ рд░реВрд╕реА рдЕрдиреБрд╡рд╛рдж рд▓рд╛рддрд╛ рд╣реВрдВ: рд╕реНрдХреИрд▓рд╛ рдореЗрдВ рдЫрдВрдЯрдиреА - рдПрдХ рдмрд┐рд▓реНрд▓реА рдХреА рджреБрдХрд╛рди рдХрд╛ рдЙрджрд╛рд╣рд░рдг ред рдпрд╣ рд▓реЗрдЦ рдЙрди рдкрд╛рдардХреЛрдВ рдХреЗ рд▓рд┐рдП рд╣реИ рдЬреЛ рд╕реНрдХрд╛рд▓рд╛ рднрд╛рд╖рд╛ рдХреЗ рд╡рд╛рдХреНрдп-рд╡рд┐рдиреНрдпрд╛рд╕ рдХреЛ рдЬрд╛рдирддреЗ рд╣реИрдВ рдФрд░ рдорд╛рдирдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рдмреБрдирд┐рдпрд╛рджреА рдЙрдкрдХрд░рдгреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░ рд╣реИрдВред
рдЗрд╕ рддрдереНрдп рдХреЗ рдмрд╛рд╡рдЬреВрдж рдХрд┐ рдЬрд╛рд╡рд╛ рдФрд░ рд╕реНрдХрд╛рд▓рд╛ рджреЛрдиреЛрдВ рдЬреЗрд╡реАрдПрдо рдХреЛ рдПрдХ рд░рдирдЯрд╛рдЗрдо рдкреНрд▓реЗрдЯрдлреЙрд░реНрдо рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рд╕реНрдХрд╛рд▓рд╛ рдиреЗ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдЕрд╡рдзрд╛рд░рдгрд╛рдУрдВ рдФрд░ рдПрдХ рд╕рдореГрджреНрдз рдорд╛рдирдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдЕрдиреБрдХреВрд▓рди рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЕрдзрд┐рдХ рдЕрднрд┐рд╡реНрдпрдВрдЬрдХ рднрд╛рд╖рд╛ рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рд╕рд┐рджреНрдзрд┐ рдкреНрд░рд╛рдкреНрдд рдХреА рд╣реИред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рдЗрд╕ рдЕрднрд┐рд╡реНрдпрдВрдЬрдирд╛ рдХреЗ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реВрдВрдЧрд╛, рдпрд╣ рдХрд▓реНрдкрдирд╛ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реВрдВрдЧрд╛ рдХрд┐ рдХреЛрдб рдЖрдзрд╛рд░ рдХрд╛ рдПрдХ рдЫреЛрдЯрд╛ рд╕рд╛ рд╣рд┐рд╕реНрд╕рд╛ рдФрд░ рдЗрд╕реА рдЖрд╡рд╢реНрдпрдХрддрд╛рдПрдВ рд╕рдордп рдХреЗ рд╕рд╛рде рдХреИрд╕реЗ рд╡рд┐рдХрд╕рд┐рдд рд╣реЛ рд╕рдХрддреА рд╣реИрдВред
рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рд╡рд┐рд╡рд░рдг
рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╣рдорд╛рд░реЗ рдирд┐рдкрдЯрд╛рди рдореЗрдВ рдПрдХ рдмрд┐рд▓реНрд▓реА рдХреА рджреБрдХрд╛рди рд╣реИ (рдХреНрдпреЛрдВрдХрд┐ рдмрд┐рд▓реНрд▓рд┐рдпрд╛рдБ рд╕реНрдХрд╛рд▓рд╛ рдкрд╛рд░рд┐рд╕реНрдерд┐рддрд┐рдХреА рддрдВрддреНрд░ рдореЗрдВ рд╕рдмрд╕реЗ рд▓реЛрдХрдкреНрд░рд┐рдп рдЬрд╛рдирд╡рд░ рд╣реИрдВ)ред рдмрд┐рдХреНрд░реА рдХреЗ рд▓рд┐рдП рдЙрдкрд▓рдмреНрдз рдмрд┐рд▓реНрд▓рд┐рдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЦрд╝рд╛рд╕рд┐рдпрдд рдХреЗ рдХрд╛рд░рдг, рдХреБрдЫ рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдирд╣реАрдВ рдЖрддреА рд╣реИ рдФрд░ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ 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 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
, . .
. , :
- .
- - ,
SortOrder.Keep
. 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 рднрдВрдбрд╛рд░ рдореЗрдВ рд╕рднреА рдирдореВрдирд╛ рдХреЛрдб рдЙрдкрд▓рдмреНрдз рд╣реИрдВ ред