Подтвердить что ты не робот

Разбить список для каждого элемента, удовлетворяющего предикату (Scala)

В текстовом файле у меня есть данные в форме:

1)
text
text
2)
more text
3)
even more text
more even text
even more text
...

Я прочитал его как список строк, используя следующее:

val input = io.Source.fromFile("filename.txt").getLines().toList

Я хочу разбить список на суб-списки, начиная с 1), 2) и т.д.

Я придумал:

val subLists =
  input.foldRight( List(List[String]()) ) {
    (x, acc) =>
      if (x.matches("""[0-9]+\)""")) List() :: (x :: acc.head) :: acc.tail
      else (x :: acc.head) :: acc.tail
  }.tail

Можно ли это сделать проще? Было бы очень приятно, если бы был встроенный метод разбиения коллекции на каждый элемент, который удовлетворяет предикату (подсказка, подсказка, дизайнеры библиотек:)).

4b9b3361

Ответ 1

foldRight со сложным аргументом, как правило, является признаком того, что вы могли бы написать это с помощью рекурсии, а также использовать его для своего метода, пока вы на нем. Вот что я придумал. Во-первых, позвольте обобщить к общему методу, groupPrefix:

 /** Returns shortest possible list of lists xss such that
  *   - xss.flatten == xs
  *   - No sublist in xss contains an element matching p in its tail
  */
 def groupPrefix[T](xs: List[T])(p: T => Boolean): List[List[T]] = xs match {
   case List() => List()
   case x :: xs1 => 
     val (ys, zs) = xs1 span (!p(_))
     (x :: ys) :: groupPrefix(zs)(p)  
 }

Теперь вы получите результат, просто позвонив

 groupPrefix(input)(_ matches """\d+\)""")