Scala的groupBy身份如何运作?

时间:2013-10-03 18:00:12

标签: scala

我正在浏览并发现了一个关于将String按字符分组的问题,例如:

输入:

"aaabbbccccdd"

会产生以下输出:

"aaa"
"bbb"
"cccc"
"ddd"

我找到了这个建议:

val str = "aaabbbccccdd"[
val list = str.groupBy(identity).toList.sortBy(_._1).map(_._2)

这位identity老乡让我很好奇。我发现它在PreDef中定义如下:

identity[A](x: A): A

所以基本上它会返回给出的任何东西,对吧?但这对groupBy的调用有何影响?

如果这是一个基本问题,我很抱歉,只是功能性编程仍然在纠缠我的大脑。如果有任何可以让我更清楚的信息,请告诉我

6 个答案:

答案 0 :(得分:10)

要理解这一点,只需使用-Xprint:typer选项调用scala repl:

val res2: immutable.Map[Char,String] = augmentString(str).groupBy[Char]({
   ((x: Char) => identity[Char](x))
});

Scalac将简单的String转换为StringOps,其中TraversableLike的子类具有groupBy方法:

def groupBy[K](f: A => K): immutable.Map[K, Repr] = {
    val m = mutable.Map.empty[K, Builder[A, Repr]]
    for (elem <- this) {
      val key = f(elem)
      val bldr = m.getOrElseUpdate(key, newBuilder)
      bldr += elem
    }
    val b = immutable.Map.newBuilder[K, Repr]
    for ((k, v) <- m)
      b += ((k, v.result))

    b.result
  }

因此groupBy包含一个映射,插入字符按标识函数返回。

答案 1 :(得分:9)

这是你的表达:

val list = str.groupBy(identity).toList.sortBy(_._1).map(_._2)

让我们逐个功能逐项。第一个是groupBy,它将使用鉴别器函数传递的键列表对您的String进行分区,在您的情况下,它是标识符。鉴别器功能将应用于屏幕中的每个字符,并且返回相同结果的所有字符将组合在一起。如果我们想将字母a与其余字母分开,我们可以使用x => x == 'a'作为我们的鉴别器函数。这会将你的字符串字符分组到map中的函数返回(true或false):

 Map(false -> bbbccccdd, true -> aaa)

使用identity,这是一种“好”的方式来说x => x,我们会得到一张地图,其中每个字符在地图中分开,在您的情况下:

Map(c -> cccc, a -> aaa, d -> dd, b -> bbb)

然后我们将地图转换为带有(char,String)的元组toList列表。

使用sortBy按字母排序,只需保留字符串,map即可获得最终结果。

答案 2 :(得分:4)

首先,让我们看看迭代字符串时会发生什么:

scala> "asdf".toList
res1: List[Char] = List(a, s, d, f)

接下来,考虑有时我们希望根据对象的某些特定属性对元素进行分组。

例如,我们可以按照长度分组字符串列表,如...

List("aa", "bbb", "bb", "bbb").groupBy(_.length)

如果您只想按项目本身对每个项目进行分组,该怎么办?您可以传递身份函数,如下所示:

List("aa", "bbb", "bb", "bbb").groupBy(identity)

你可以做一些像这样的傻事,但这很愚蠢:

List("aa", "bbb", "bb", "bbb").groupBy(_.toString)

答案 3 :(得分:1)

看看

str.groupBy(identity)

返回

scala.collection.immutable.Map[Char,String] = Map(b -> bbb, d -> dd, a -> aaa, c -> cccc)

因此元素分组的关键是字符。

答案 4 :(得分:1)

每当您尝试在String上使用groupBy等方法时。重要的是要注意它隐式转换为StringOps List[Char]

StringOps

groupBy的签名由 -

给出
def groupBy[K](f: (Char) ⇒ K): Map[K, String]

因此,结果的形式为 -

Map[Char,String]

列表[字符]

groupBy的签名由 -

给出
def groupBy[K](f: (Char) ⇒ K): Map[K, List[Char]]

如果它已隐式转换为List[Char],则结果将为 -

Map[Char,List[Char]]

现在这应该隐含地回答你的好奇问题,就像scala在groupBy Char上找到Map[Char, String](见签名)然后给你{{1}}。

答案 5 :(得分:0)

基本上list.groupBy(identity)只是说list.groupBy(x => x)的一种奇特方式,在我看来,这更清晰。它将包含重复项目的列表按这些项目分组。