【问题标题】:How to sort scala list dynamically on multiple fields如何在多个字段上动态排序scala列表
【发布时间】:2019-12-19 15:28:50
【问题描述】:

我有一个案例类

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。

这可以实现吗??

【问题讨论】:

  • 也许只是一个接一个地做多个sortBy
  • @amer 当然,第二个 sortBy 会破坏第一个创建的顺序。
  • @AlexeyRomanov 不,不会,因为sortBy 是稳定的。您只需要首先按最不重要的字段进行排序。在这个例子中,顺序是joinedDate 然后age 然后name

标签: scala sorting dynamic collections


【解决方案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"))

将其扩展为处理降序列作为练习。

【讨论】:

    【解决方案2】:

    您可以使用Ordering.by 定义Employee 的排序,将其视为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)
    )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-12-07
      • 2018-08-26
      • 2011-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多