группирование элементов в итерируемое путем поиска значения часового (в Scala) - PullRequest
5 голосов
/ 12 июля 2010

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

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)
}

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

Ответы [ 2 ]

5 голосов
/ 13 июля 2010

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

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]())
    }
  }
2 голосов
/ 13 июля 2010

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

  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
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...