2

I have the following class :

final case class PowerDetails (
  [...],
  label: String,
  title: String,
  category: String,
  idCategory: Option[String],
  numCategory: Option[Int]
)

I need to sort a list of PowerDetails like this :

Elements having a value for idCategory and numCategory should be before the None , and ordered by idCategory and then numCategory. As for the None values, they need to be ordered by the fields category , title , label.

If possible, I would like to avoid extending Ordered

final case class PowerDetails (

   ...

) extends Ordered[PowerDetails] {

    override def compare(that: PowerDetails): Int = {
       // Define here the comparison
    }

}

I tried creating an Ordering as below and then use the sorted function, but I'm getting a NullPointerException

  implicit val orderingPowers = optionOrdering.thenComparing(ordering)

  val ordering: Ordering[PowerDetails] = Ordering[(String, String, String)]
    .on[PowerDetails](powerDetail =>
      ( powerDetail.category, powerDetail.title, powerDetail.label))

  val optionOrdering : Ordering[PowerDetails] = Ordering[(Option[String], Option[Int])]
    .on[PowerDetails](powerDetail =>
      (powerDetail.idCategory, powerDetail.numCategory))

Could you please help me find out how to do it ? Thanks.

sewey
  • 51
  • 3
  • 9

2 Answers2

3

Here's another approach also using Ordering.by along with Option's isEmpty, leveraging false < true for the wanted Some/None ordering:

final case class PowerDetails (
  field1: String,
  field2: Int,
  label: String,
  title: String,
  category: String,
  idCategory: Option[String],
  numCategory: Option[Int]
)

implicit val PDOrderer: Ordering[PowerDetails] = Ordering.by{
  case PowerDetails(_, _, label, title, cat, idCat, numCat) =>
    (idCat.isEmpty, idCat, numCat.isEmpty, numCat, cat, title, label)
}
Leo C
  • 22,006
  • 3
  • 26
  • 39
2

Would this work for you?

implicit val PDOrd :Ordering[PowerDetails] = Ordering.by(
  pd => (pd.idCategory.getOrElse("~~~~")
       , pd.numCategory.getOrElse(Int.MaxValue)
       , pd.category
       , pd.title
       , pd.label ))

Admittedly "~~~~" isn't the end of the String universe, but it should work in most cases.

jwvh
  • 50,871
  • 7
  • 38
  • 64
  • thanks, but I'd rather not use `getOrElse`. I'll keep it in mind though, if I can't find anything else – sewey Jan 29 '20 at 20:03