У меня есть итератор строк из очень большого файла, который должен быть помещен в группы, поскольку я прохожу. Я знаю, где каждая группа заканчивается, потому что существует значение сигнальной метки на последней строке каждой группы. Так в основном я хочу записать функцию, которая берет итератор и значение сигнальной метки, и возвращает итератор групп каждый завершенный значением сигнальной метки. Что-то как:
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)
}
Я думаю, что это будет работать, и я предполагаю, что это прекрасно, но имеющий необходимость повторно добавить сигнальную метку каждый раз дает мне запах кода. Существует ли лучший способ сделать это?
Уродливо, но должно быть более производительным, чем ваше решение:
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
}
Менее читаема, чем ваша, но более "правильная", когда конечная группа не имеет конечного сигнального значения:
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]())
}
}