Как работает идентификатор 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), что, на мой взгляд, более понятно. Он группирует список, содержащий повторяющиеся элементы по этим элементам.