22

このコードは 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 はマップを返しますが、要素の順序が以前とは異なっていることに気付くでしょう。なぜこれが起こるのか、これを回避する最善の方法は何ですか?

4

2 に答える 2

21

特に SortedMap のサブタイプを使用しない限り、マップ (セットなど) は常に未指定の順序になります。「groupBy」はSortedMapを返さず、一般的なimmutable.Mapのみを返し、CanBuildFromメカニズムも使用しないため、ここでできることは何もないと思います。

このトピックの詳細については、同様の質問への回答を参照してください

編集:

後でマップをSortedMap(キー順)に変換したい場合は、SortedMap(l.groupBy(_.a).toSeq:_*)(を使用してimport scala.collection.immutable.SortedMap)行うことができます。...toSeq.sortWith(...).toMap結果のマップでの順序が保証されないため、実行しないでください。

于 2013-01-21T07:35:15.490 に答える
11

データベースのレコードを扱うとき、私はいつもこれに出くわします。データベースはそれらを何らかのキーでソートしますが、groupBy はそれを元に戻します! そこで、連続した等号キーでグループ化する関数を使用して Sequence クラスをポンピングし始めました。

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)
于 2013-07-16T17:45:23.777 に答える