группировка объектов в повторяемом путем поиска значения сигнальной метки (в scala)

У меня есть итератор строк из очень большого файла, который должен быть помещен в группы, поскольку я прохожу. Я знаю, где каждая группа заканчивается, потому что существует значение сигнальной метки на последней строке каждой группы. Так в основном я хочу записать функцию, которая берет итератор и значение сигнальной метки, и возвращает итератор групп каждый завершенный значением сигнальной метки. Что-то как:

scala> groups("abc.defg.hi.jklmn.".iterator, '.')
res1: Iterator[Seq[Char]] = non-empty iterator

scala> groups("abc.defg.hi.jklmn.".iterator, '.').toList
res19: List[Seq[Char]] = List(List(a, b, c, .), List(d, e, f, g, .), List(h, i, .), List(j, k, l, m, n, .))

Обратите внимание, что я хочу объекты сигнальной метки, включенные в конце каждой из групп. Вот мое текущее решение:

def groups[T](iter: Iterator[T], sentinel: T) = new Iterator[Seq[T]] {                   
  def hasNext = iter.hasNext
  def next = iter.takeWhile(_ != sentinel).toList ++ List(sentinel)
}

Я думаю, что это будет работать, и я предполагаю, что это прекрасно, но имеющий необходимость повторно добавить сигнальную метку каждый раз дает мне запах кода. Существует ли лучший способ сделать это?

5
задан Steve 12 July 2010 в 18:33
поделиться

2 ответа

Уродливо, но должно быть более производительным, чем ваше решение:

  def groups[T](iter: Iterator[T], sentinel: T) = new Iterator[Seq[T]] {                   
    def hasNext = iter.hasNext
    def next = iter.takeWhile{
      var last = null.asInstanceOf[T]
       c => { val temp = last; last = c; temp != sentinel}
     }.toList
  }
2
ответ дан 14 December 2019 в 08:40
поделиться

Менее читаема, чем ваша, но более "правильная", когда конечная группа не имеет конечного сигнального значения:

def groups[T](iter: Iterator[T], sentinel: T) = new Iterator[Seq[T]] {
 def hasNext = iter.hasNext
 def next: Seq[T] = {
     val builder = scala.collection.mutable.ListBuffer[T]()
     while (iter.hasNext) {
       val x = iter.next
       builder.append(x)
       if (x == sentinel) return builder
     }
     builder
 }
}

Или рекурсивно:

  def groups[T](iter: Iterator[T], sentinel: T) = new Iterator[Seq[T]] {
    def hasNext = iter.hasNext
    def next: Seq[T] = {
      @scala.annotation.tailrec
      def build(accumulator: ListBuffer[T]): Seq[T] = {
        val v = iter.next
        accumulator.append(v)
        if (v == sentinel || !iter.hasNext) => accumulator
        else build(accumulator)
      }
      build(new ListBuffer[T]())
    }
  }
5
ответ дан 14 December 2019 в 08:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: