Why does groupBy in Scala change the ordering of a list's items?

后端 未结 2 1627
陌清茗
陌清茗 2020-12-15 05:11

This code is from a Scala Worksheet:

case class E(a: Int, b: String)

val l = List(
    E(1, \"One\"),
    E(1, \"Another One\"),
    E(2, \"Two\"),
    E(2,         


        
相关标签:
2条回答
  • 2020-12-15 05:54

    I run into this all the time when dealing with database records. The database sorts them by some key but then groupBy undoes it! So I've started pimping the Sequence class with a function that groups by consecutive equal keys:

    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)
    }
    

    To use it:

    import util.PimpedSeq._   // implicit conversion    
    val dbRecords = db.getTheRecordsOrderedBy
    val groups = dbRecords.groupConsecutiveKeys(r => r.getKey)
    
    0 讨论(0)
  • 2020-12-15 06:13

    Unless you specifically use a subtype of SortedMap, a map (like a set) is always in an unspecified order. Since "groupBy" doesn't return a SortedMap but only a general immutable.Map and also doesn't use the CanBuildFrom mechanism, I think there's nothing that you can do here.

    You can find more on this topic in answers to similar questions, e.g. here.

    Edit:

    If you want to convert the map afterwarts to a SortedMap (ordered by its keys), you can do SortedMap(l.groupBy(_.a).toSeq:_*) (with import scala.collection.immutable.SortedMap). Don't do ...toSeq.sortWith(...).toMap because that will not guarantee the ordering in the resulting map.

    0 讨论(0)
提交回复
热议问题