在Scala中按列表排序

时间:2015-01-16 18:46:23

标签: scala sorting

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

如何进行此类排序?

1 个答案:

答案 0 :(得分:3)

解决此问题最直接的方法可能是使用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