Как работает идентификатор Scala groupBy?

Я просматривал и нашел вопрос о группировке 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?

Извините, если это основной вопрос, просто функциональное программирование по-прежнему немного запутывает мои мозги. Пожалуйста, дайте мне знать, если есть какая-либо информация, которую я могу дать, чтобы сделать этот вопрос яснее

Ответ 1

Чтобы понять это, просто позвоните scala с помощью опции -Xprint:typer:

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 содержит карту, в которую вставляются символы, возвращаемые с помощью функции идентификации.

Ответ 2

Это ваше выражение:

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

Отпустите элемент по функциям. Первый из них - groupBy, который разбивает вашу строку, используя список ключей, передаваемых функцией дискриминатора, которая в вашем случае является личным. Функция дискриминатора будет применена к каждому символу на экране, и все символы, возвращающие один и тот же результат, будут сгруппированы вместе. Если мы хотим отделить букву а от остальных, мы могли бы использовать x => x == 'a' как нашу дискриминаторную функцию. Это сгруппировало бы ваши строковые символы в возврате этой функции (true или false) на карте:

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

Используя identity, который является "хорошим" способом сказать x => x, мы получаем карту, где каждый символ разделяется на карте, в вашем случае:

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

Затем преобразуем карту в список кортежей (char,String) с toList.

Закажите его char с помощью sortBy и просто держите String с map получая окончательный результат.

Ответ 3

Во-первых, посмотрим, что произойдет, когда вы перейдете по строке:

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)

Ответ 4

Взгляните на

str.groupBy(identity)

который возвращает

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

поэтому ключ, по которому группируются элементы, является символом.

Ответ 5

Всякий раз, когда вы пытаетесь использовать такие методы, как groupBy для строки. Важно отметить, что он неявно преобразован в StringOps и не List[Char].

StringOps

Подпись groupBy задается как

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

Следовательно, результат имеет вид -

Map[Char,String]

Список [ Char]

Подпись groupBy задается как

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

Если бы он был неявно преобразован в List[Char], результат был бы формы -

Map[Char,List[Char]]

Теперь это должно неявно ответить на ваш любопытный вопрос, как scala понял groupBy на Char (см. подпись) и еще дал вам Map[Char, String].

Ответ 6

По сути, list.groupBy(identity) - это просто причудливый способ сказать list.groupBy(x => x), что, на мой взгляд, более понятно. Он группирует список, содержащий повторяющиеся элементы по этим элементам.