Как работает эта строка кода c? - PullRequest
0 голосов
/ 09 января 2020

Я новичок в Scala, и недавно я прошел через http://aperiodic.net/phil/scala/s-99/p09.scala и пытался решить проблему.

Вопрос: Упакуйте последовательные дубликаты элементов списка в подсписки. Если список содержит повторяющиеся элементы, они должны быть помещены в отдельные подсписки.

scala> pack(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e))
res0: List[List[Symbol]] = List(List('a, 'a, 'a, 'a), List('b), List('c, 'c), List('a, 'a), List('d), List('e, 'e, 'e, 'e))

Решение:

object P09 {
  def pack[A](ls: List[A]): List[List[A]] = {
    if (ls.isEmpty) List(List())
    else {
      val (packed, next) = ls span { _ == ls.head }
      if (next == Nil) List(packed)
      else packed :: pack(next)
    }
  }
}

Мой вопрос: что на самом деле делает строка кода ниже? Как это работает?

val(packed, next) = l span {_ == l.head}

Ответы [ 3 ]

2 голосов
/ 09 января 2020

Предположим, items = xs ++ List(y) ++ zs, где все элементы в xs удовлетворяют некоторому предикату pred, а y делает , а не удовлетворяет pred. В этом случае

items.span(pred) => (xs, List(y) ++ zs)

Итак, что делает ваша строка кода l span {_ == l.head}, это извлекает все равные элементы из начала списка в первый список packed, а все остальные элементы во второй список next.

1 голос
/ 09 января 2020

Первый метод span создает только две коллекции: одна удовлетворяет условию, а вторая - нет.

val(packed, next) = l span {_ == l.head}

Здесь _ - синтакт c сахара Scala. Это так же, как l.span(e => e == l.head). Поскольку Scala очень лаконичен, он обеспечивает синтактику c сахаров. Вам не нужно использовать имя переменных, таких как e. Метод span получает значения из списка и применяет к нему фильтр. Он фильтрует все элементы списка в одной коллекции, которая равна значению первого элемента списка.

Надеюсь, это поможет.

1 голос
/ 09 января 2020

Ну, как мы видим на странице ScalaDocs ...

def span(p: (A) => Boolean): (List[A], List[A])

... span() разбивает список ls на 2 списка. Первый список, packed, состоит из всех начальных элементов, которые удовлетворяют условию предиката, == ls.head. 2-й список, next, является остальной частью списка ls, который не вошел в 1-ю группу, то есть 1-й элемент, который не удовлетворял условию предиката, и все, что после этого.

Вот более краткое выражение того же алгоритма.

def pack[A](ls: List[A]): List[List[A]] = List.unfold(ls){  //<--Scala 2.13
  case Nil => None
  case lst => Some(lst.span(_ == lst.head))
}
...