如何在多个字段上动态排序scala列表

时间:2019-12-19 15:28:50

标签: scala sorting dynamic collections

我有一个案例课

case class Employee(name: String, age: Int, joinedDate: Instant)

我有一个员工列表

val employees: List[Employee]

可容纳多名员工。

我想基于多个字段对列表进行排序,例如,当多个雇员具有相同的姓名时,排序应基于年龄,类似地,当他们具有相同的年龄时,排序应基于joinedDate,这意味着我需要多级排序。排序参数可以是任意顺序。

scala中有一个sortBy方法,它可以对多列进行排序,即      employees.sortBy(e => (e.name, e.age))。但这是静态的,我需要动态。请注意,排序字段具有不同的数据类型,例如Instant,Int和String。

这可以实现吗?

2 个答案:

答案 0 :(得分:1)

您可以动态建立Ordering[Employee]。例如。 :

val orderings = Map(
  "name" -> Ordering.by[Employee](_.name),
  "age" -> Ordering.by[Employee](_.age),
  "joinedDate" -> Ordering.by[Employee](_.joinedDate)
)

def orderingByColumns(columns: Seq[String]) = columns.map(orderings).reduce(_.orElse(_))

您可以通过调用sorted并明确传递顺序来使用它:

employees.sorted(orderingByColumns(List("name", "age"))

将其扩展以处理降序列是一项练习。

答案 1 :(得分:1)

您可以使用Ordering.byEmployee定义为Tuple的顺序:

import java.time.Instant
case class Employee(name: String, age: Int, joinedDate: Instant)

implicit val employeeOrdering: Ordering[Employee] = Ordering.by(Employee.unapply)

测试订单:

def toInstant(s: String): Instant = {
  import java.time.{LocalDateTime, ZoneId}
  import java.time.format.DateTimeFormatter
  val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")      
  LocalDateTime.parse(s, formatter).atZone(ZoneId.of("America/Los_Angeles")).toInstant
}

val employees = List(
  Employee("John", 30, toInstant("2019-01-02 00:00:00")),
  Employee("Sue",  20, toInstant("2019-01-02 00:00:00")),
  Employee("Dave", 45, toInstant("2019-01-01 00:00:00")),
  Employee("Amy",  25, toInstant("2019-01-01 00:00:00")),
  Employee("John", 20, toInstant("2019-01-03 00:00:00"))
)

employees.sorted
// res1: List[Employee] = List(
//   Employee("Amy",  25, 2019-01-01T08:00:00Z),
//   Employee("Dave", 45, 2019-01-01T08:00:00Z),
//   Employee("John", 20, 2019-01-03T08:00:00Z),
//   Employee("John", 30, 2019-01-02T08:00:00Z),
//   Employee("Sue",  20, 2019-01-02T08:00:00Z)
// )

作为补充,如果需要不同的顺序(例如joinedDate, name, age

implicit val employeeOrdering: Ordering[Employee] = Ordering.by(
  e => (e.joinedDate, e.name, e.age)
)