在 Scala 中按列表排序

Sorting by list in Scala

我最近遇到这个问题:JPA: How do I sort on a Set field in my entity?
我开始思考如何在 Scala 中完成类似的排序。
所以我们有一个用户列表。每个用户都有组织的排序列表。我们想按组织名称列表对这个用户列表进行排序。用户按第一个组织名称排序,当名字相同时,则按第二个名字进行比较,依此类推。
我已经设法编写了这样的排序,但在某些情况下它给出了错误的结果。

class Organization (aId: Int, aName: String) { 
    val id:Int = aId
    var name:String = aName
} 

class User (aId: Int, aOrganizations: List[Organization]) { 
    val id:Int = aId
    var organizations:List[Organization] = aOrganizations
} 

val o1 = new Organization(1, "AAA")
val o2 = new Organization(2, "AAAA")
val o3 = new Organization(3, "BBB")
val o4 = new Organization(4, "BBBB")
val o5 = new Organization(5, "CCC")
val o6 = new Organization(6, "AAA BBB")

val u1  = new User(1,  List(o1))
val u2  = new User(2,  List(o2))
val u3  = new User(3,  List(o3))
val u4  = new User(4,  List(o4))
val u5  = new User(5,  List(o1,o5))
val u6  = new User(6,  List(o2,o3))
val u7  = new User(7,  List(o3,o4))
val u8  = new User(8,  List(o1,o2,o3,o4))
val u9  = new User(9,  List(o1,o2,o3,o5))
val u10 = new User(10, List())
val u11 = new User(11, List(o6))

val users = List(u1, u2, u3, u4, u5, u6, u7, u8, u9, u10, u11)

// below line should be improved
val sortedUsers = users.sortWith(_.organizations.foldLeft("")((b,a) => b + a.name + ",") < _.organizations.foldLeft("")((b,a) => b + a.name + ",")) 

sortedUsers.foreach{ x => print(x.id+" ")}

// received result: 10 11 1 8 9 5 2 6 3 7 4
// expected result: 10 1 8 9 5 11 2 6 3 7 4

如何进行排序?

解决这个问题最直接的方法可能是使用 sortBy 而不是 sortWith。 Scala 为 Iterable[A] 提供了一个字典排序实例,其中 A 有一个排序实例,所以你只需要为 Organization:

提供一个排序实例
implicit val organizationOrdering: Ordering[Organization] =
  Ordering.by(_.name)

val sortedUsers = users.sortBy(_.organizations.toIterable)

您也可以只为 User 提供一个实例,然后使用 sorted:

implicit val organizationOrdering: Ordering[Organization] =
  Ordering.by(_.name)

implicit val userOrdering: Ordering[User] =
  Ordering.by(_.organizations.toIterable)

val sortedUsers = users.sorted

如果你不想引入这些实例,你可以显式传递你需要的那个:

val sortedUsers = users.sortBy(_.organizations.toIterable)(
  Ordering.Iterable(Ordering.by(_.name))
)

遗憾的是没有 List[A: Ordering] 的实例,但显然有 good reasons for that