在 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。
我最近遇到这个问题: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。