Преобразование итератора в итератор кусков дубликатов - PullRequest
1 голос
/ 02 февраля 2020

Предположим, я пишу функцию foo: Iterator[A] => Iterator[List[A]] для преобразования заданного итератора в итератор кусков дубликатов:

def foo[T](it: Iterator[A]): Iterator[List[A]] = ???
foo("abbbcbbe".iterator).toList.map(_.mkString) // List("a", "bbb", "c", "bb", "e")

Для реализации foo Я хочу использовать функцию splitDupes: Iterator[A] => (List[A], Iterator[A]), которая разбивает итератор на префикс с дубликатами и остальным (большое спасибо Колмару , который предложил это здесь )

def splitDupes[A](it: Iterator[A]): (List[A], Iterator[A]) = {
  if (it.isEmpty) {
    (Nil, Iterator.empty)
  } else {
    val head = it.next
    val (dupes, rest) = it.span(_ == head)
    (head +: dupes.toList, rest)
  }
}

Теперь я пишу foo используя splitDupes вот так:

def foo[A](it: Iterator[A]): Iterator[List[A]] = {
   if (it.isEmpty) {
     Iterator.empty
   } else {
     val (xs, ys) = Iterator.iterate(splitDupes(it))(x => splitDupes(x._2)).span(_._2.nonEmpty)
     (if (ys.hasNext) xs ++ Iterator(ys.next) else xs).map(_._1)
   }
}

Эта реализация кажется работающей, но выглядит сложной и неуклюжей.
Как бы вы улучшили реализацию foo выше?

1 Ответ

1 голос
/ 02 февраля 2020

Вы можете сделать это так:

def foo[A](it: Iterator[A]): Iterator[List[A]] = {
  Iterator.iterate(splitDupes(it))(x => splitDupes(x._2))
    .map(_._1)
    .takeWhile(_.nonEmpty)
}

Пустой регистр уже обработан в splitDupes. Вы можете безопасно продолжать вызывать splitDupes, пока он не достигнет этого пустого регистра (то есть начнет возвращать Nil в первом элементе кортежа).

Это работает нормально во всех случаях:

scala> foo("abbbcbbe".iterator).toList.map(_.mkString)
res1: List[String] = List(a, bbb, c, bb, e)

scala> foo("".iterator).toList.map(_.mkString)
res2: List[String] = List()

scala> foo("a".iterator).toList.map(_.mkString)
res3: List[String] = List(a) 

scala> foo("aaa".iterator).toList.map(_.mkString)
res4: List[String] = List(aaa)

scala> foo("abc".iterator).toList.map(_.mkString)
res5: List[String] = List(a, b, c)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...