Scala的groupBy身份如何运作?

Rod*_*aki 18 scala

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

输入:

"aaabbbccccdd"
Run Code Online (Sandbox Code Playgroud)

会产生以下输出:

"aaa"
"bbb"
"cccc"
"ddd"
Run Code Online (Sandbox Code Playgroud)

我发现了这个建议:

val str = "aaabbbccccdd"[
val list = str.groupBy(identity).toList.sortBy(_._1).map(_._2)
Run Code Online (Sandbox Code Playgroud)

这个identity家伙让我很好奇.我发现它的定义PreDef如下:

identity[A](x: A): A
Run Code Online (Sandbox Code Playgroud)

所以基本上它会返回给出的任何东西,对吧?但这怎么适用于电话groupBy

我很抱歉,如果这是一个基本问题,那就是功能性编程仍然让我的脑子有点紧张.如果有任何信息可以让我更清楚,请告诉我

4le*_*x1v 11

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

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

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
  }
Run Code Online (Sandbox Code Playgroud)

因此groupBy包含一个映射,插入字符通过标识函数返回到该映射.


Vin*_*ana 10

这是你的表达:

val list = str.groupBy(identity).toList.sortBy(_._1).map(_._2)
Run Code Online (Sandbox Code Playgroud)

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

 Map(false -> bbbccccdd, true -> aaa)
Run Code Online (Sandbox Code Playgroud)

通过使用identity,这是一个"好"的方式x => x,我们得到一个地图,其中每个角色在地图中分开,在您的情况下:

Map(c -> cccc, a -> aaa, d -> dd, b -> bbb)
Run Code Online (Sandbox Code Playgroud)

然后,我们在地图转换成一个元组列表(char,String)toList.

通过char对它进行排序,sortBy只需保留String即可map获得最终结果.


Lar*_*nal 6

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

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

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

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

List("aa", "bbb", "bb", "bbb").groupBy(_.length)
Run Code Online (Sandbox Code Playgroud)

如果您只是想按项目本身将每个项目分组。您可以这样传递身份函数:

List("aa", "bbb", "bb", "bbb").groupBy(identity)
Run Code Online (Sandbox Code Playgroud)

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

List("aa", "bbb", "bb", "bbb").groupBy(_.toString)
Run Code Online (Sandbox Code Playgroud)