此代码来自Scala工作表:
case class E(a: Int, b: String)
val l = List(
E(1, "One"),
E(1, "Another One"),
E(2, "Two"),
E(2, "Another Two"),
E(3, "Three")
)
l.groupBy(x => x.a)
// res11: scala.collection.immutable.Map[Int,List[com.dci.ScratchPatch.E]] =
// Map(
// 2 -> List(E(2,Two), E(2,Another Two)),
// 1 -> List(E(1,One), E(1,Another One)),
// 3 -> List(E(3,Three))
// )
您会注意到groupBy返回一个地图,但现在元素的顺序与之前的顺序不同。知道为什么会发生这种情况,以及避免这种情况的最佳方法是什么?
答案 0 :(得分:20)
除非您专门使用SortedMap的子类型,否则地图(如集合)始终采用未指定的顺序。由于“groupBy”不返回SortedMap而只返回一般的immutable.Map,也没有使用CanBuildFrom机制,因此我认为你无法在这里做任何事情。
您可以在类似问题的答案中找到有关此主题的更多信息,例如: here
修改强>
如果您想将地图后贴图转换为SortedMap(按其键排序),您可以执行SortedMap(l.groupBy(_.a).toSeq:_*)
(import scala.collection.immutable.SortedMap
)。不要...toSeq.sortWith(...).toMap
,因为这不能保证生成的地图中的排序。
答案 1 :(得分:10)
我在处理数据库记录时一直遇到这种情况。数据库按一些键对它们进行排序,然后groupBy撤消它!所以我开始使用一个按连续相等键分组的函数对Sequence类进行pimping:
class PimpedSeq[A](s: Seq[A]) {
/**
* Group elements of the sequence that have consecutive keys that are equal.
*
* Use case:
* val lst = SQL("SELECT * FROM a LEFT JOIN b ORDER BY a.key")
* val grp = lst.groupConsecutiveKeys(a.getKey)
*/
def groupConsecutiveKeys[K](f: (A) => K): Seq[(K, List[A])] = {
this.s.foldRight(List[(K, List[A])]())((item: A, res: List[(K, List[A])]) =>
res match {
case Nil => List((f(item), List(item)))
case (k, kLst) :: tail if k == f(item) => (k, item :: kLst) :: tail
case _ => (f(item), List(item)) :: res
})
}
}
object PimpedSeq {
implicit def seq2PimpedSeq[A](s: Seq[A]) = new PimpedSeq(s)
}
使用它:
import util.PimpedSeq._ // implicit conversion
val dbRecords = db.getTheRecordsOrderedBy
val groups = dbRecords.groupConsecutiveKeys(r => r.getKey)