Scala GroupBy preserving insertion order?

后端 未结 4 1409
囚心锁ツ
囚心锁ツ 2020-12-29 21:06

The groupBy method in Lists, Maps, etc., generate a Map after the function.

Is there a way to use the groupBy to generate a Map that preserves insertion order (Link

4条回答
  •  暗喜
    暗喜 (楼主)
    2020-12-29 21:55

    The following would give you a groupByOrderedUnique method that behaves as you sought. It also adds a groupByOrdered that preserves duplicates as others have asked for in the comments.

    import collection.immutable.ListSet
    import collection.mutable.{LinkedHashMap => MMap, Builder}
    
    implicit class GroupByOrderedImplicitImpl[A](val t: Traversable[A]) extends AnyVal {
      def groupByOrderedUnique[K](f: A => K): Map[K, ListSet[A]] =
        groupByGen(ListSet.newBuilder[A])(f)
    
      def groupByOrdered[K](f: A => K): Map[K, List[A]] =
        groupByGen(List.newBuilder[A])(f)
    
      def groupByGen[K, C[_]](makeBuilder: => Builder[A, C[A]])(f: A => K): Map[K, C[A]] = {
        val map = MMap[K, Builder[A, C[A]]]()
        for (i <- t) {
          val key = f(i)
          val builder = map.get(key) match {
            case Some(existing) => existing
            case None =>
              val newBuilder = makeBuilder
              map(key) = newBuilder
              newBuilder
          }
          builder += i
        }
        map.mapValues(_.result).toMap
      }
    }
    

    When I use that code like:

    import GroupByOrderedImplicit._
      
    val range = 0.until(40)
    val in = range ++ range.reverse
      
    println("With dupes:")
    in.groupByOrdered(_ % 10).toList.sortBy(_._1).foreach(println)
      
    println("\nUnique:")
    in.groupByOrderedUnique(_ % 10).toList.sortBy(_._1).foreach(println)
    

    I get the following output:

    With dupes:
    (0,List(0, 10, 20, 30, 30, 20, 10, 0))
    (1,List(1, 11, 21, 31, 31, 21, 11, 1))
    (2,List(2, 12, 22, 32, 32, 22, 12, 2))
    (3,List(3, 13, 23, 33, 33, 23, 13, 3))
    (4,List(4, 14, 24, 34, 34, 24, 14, 4))
    (5,List(5, 15, 25, 35, 35, 25, 15, 5))
    (6,List(6, 16, 26, 36, 36, 26, 16, 6))
    (7,List(7, 17, 27, 37, 37, 27, 17, 7))
    (8,List(8, 18, 28, 38, 38, 28, 18, 8))
    (9,List(9, 19, 29, 39, 39, 29, 19, 9))
    
    Unique:
    (0,ListSet(0, 10, 20, 30))
    (1,ListSet(1, 11, 21, 31))
    (2,ListSet(2, 12, 22, 32))
    (3,ListSet(3, 13, 23, 33))
    (4,ListSet(4, 14, 24, 34))
    (5,ListSet(5, 15, 25, 35))
    (6,ListSet(6, 16, 26, 36))
    (7,ListSet(7, 17, 27, 37))
    (8,ListSet(8, 18, 28, 38))
    (9,ListSet(9, 19, 29, 39))
    

提交回复
热议问题