问题
How to split an iterator into a prefix with duplicates and the rest ? For instance,
def splitDupes(it: Iterator[Int]): (Iterator[Int], Iterator[Int]) = ???
val (xs, ys) = splitDupes(List(1, 1, 1, 2, 3, 4, 5).iterator)
xs.toList // List(1, 1, 1)
ys.toList // List(2, 3, 4, 5)
val (xs, ys) = splitDupes(List(1, 2, 3, 4, 5).iterator)
xs.toList // List(1)
ys.toList // List(2, 3, 4, 5)
val (xs, ys) = splitDupes(List(1, 1, 1, 1, 1).iterator)
xs.toList // List(1, 1, 1, 1, 1)
ys.toList // List()
val (xs, ys) = splitDupes(List[Int]().iterator)
xs.toList // List()
ys.toList // List()
Can I use it to read a text file by chunks ?
回答1:
You can use the span
method to split an Iterable
into a prefix that satisfies a predicate and a suffix that doesn't. For Iterator
s span
does the correct thing, and lazily stores elements in the prefix Iterator
, in case the suffix was iterated before the prefix has run out.
def splitDupes[T](it: Iterator[T]): (Iterator[T], Iterator[T]) = {
if (it.isEmpty) (Iterator.empty, Iterator.empty)
else {
val head = it.next()
val (dupes, rest) = it.span(_ == head)
(Iterator(head) ++ dupes, rest)
}
}
Example:
scala> val (dupes, rest) = splitDupes(Iterator(1,1,1,2,3,2,1))
dupes: Iterator[Int] = <iterator>
rest: Iterator[Int] = <iterator>
scala> (dupes.toList, rest.toList)
res1: (List[Int], List[Int]) = (List(1, 1, 1),List(2, 3, 2, 1))
回答2:
What about something like this?
(Note: I decided to return a plain List as the first part since that would already been consumed)
def splitDupes[A](it: Iterator[A]): (List[A], Iterator[A]) = {
it.nextOption() match {
case Some(head) =>
@annotation.tailrec
def loop(count: Int): (List[A], Iterator[A]) =
it.nextOption() match {
case Some(x) if (x == head) =>
loop(count + 1)
case Some(x) =>
List.fill(count)(head) -> Iterator(Iterator.single(x), it).flatten
case None =>
List.fill(count)(head) -> Iterator.empty
}
loop(count = 1)
case None =>
List.empty -> Iterator.empty
}
}
来源:https://stackoverflow.com/questions/59142798/how-to-split-up-an-iterator