22

我正在浏览并发现一个关于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

如果这是一个基本问题,我很抱歉,只是函数式编程仍然让我有点纠结。请让我知道是否有任何信息可以让这个问题更清楚

4

6 回答 6

14

这是你的表达:

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

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

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

通过使用identity,这是一种“很好”的说法x => x,我们得到了一个地图,其中每个字符在地图中被分开,在你的情况下:

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

然后我们将映射转换为元组(char,String) 列表toList

用 char 对其进行排序,sortBy并保留 String 以map获得最终结果。

于 2013-10-03T19:02:20.713 回答
13

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

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

Scalac 将一个 simpleString转换为StringOpswith 是一个子类,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 包含一个映射,其中插入由标识函数返回的字符。

于 2013-10-03T18:43:07.287 回答
8

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

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)
于 2013-10-03T18:09:36.323 回答
3

看一眼

str.groupBy(identity)

返回

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

所以元素分组的关键是字符。

于 2013-10-03T18:11:10.640 回答
1

每当您尝试使用诸如groupBy在字符串上的方法时。需要注意的是,它被隐式转换为StringOpsand not List[Char]

字符串操作

的签名由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 是如何想出groupByon Char(见签名)并给你Map[Char, String].

于 2013-10-03T18:41:23.530 回答
0

基本上 list.groupBy(identity) 只是 list.groupBy(x => x) 的一种说法,在我看来更清楚。它按这些项目对包含重复项目的列表进行分组。

于 2019-06-20T20:10:17.907 回答