我有一个很长的集合,我需要在scala中迭代,我想避免将它全部保存在内存中。我想出的解决方案就是:
(rows是我正在尝试处理的迭代器,COMPONENT_LIMIT是我计算的可以保留在内存中的对象的估计值)
val ( processItr, countItr ) = rows.duplicate
val pastLimitItr = countItr.drop( COMPONENT_LIMIT )
if ( pastLimitItr.hasNext )
new CustomIterator( processItr.buffered)
else
Iterator( MappperToObject.createObject(
processItr.toList
) )
我遇到的问题是:即使我不再需要使用pastLimitItr,据我所知scala source on def duplicate,队列会挂起,所以使用的内存相对于长度迭代器。
问题是:在完成测试后,如何在def副本中删除Partner对象中的队列?测试后我根本不需要复制品。
更新:我应该补充一点,输出迭代器对象将根据其内容包含输入迭代器中的一些对象,因此我不能按照建议使用分组。
更新:看起来span是答案中给出的选项中的正确答案。我的问题可能不够具体。
答案 0 :(得分:2)
听起来你想要使用:
val segments = iterator.grouped(LIMIT)
createObject(segments.next())
虽然您确实需要duplicate
,但您可以排除重复项。
您还可以使用条件重要的iterator.span
:
scala> val it = (1 to 10).iterator
it: Iterator[Int] = non-empty iterator
scala> var n = 0 ; val (vs, rest) = it.span { _ => n += 1; n < 3 }
n: Int = 0
vs: Iterator[Int] = non-empty iterator
rest: Iterator[Int] = unknown-if-empty iterator
scala> vs.toList
res0: List[Int] = List(1, 2)
scala> rest.toList
res1: List[Int] = List(3, 4, 5, 6, 7, 8, 9, 10)
您可以将其定义为Iterator::splitAt
:
scala> implicit class splitItAt[A](it: Iterator[A]) {
| def splitAt(i: Int): (Iterator[A], Iterator[A]) = {
| var n = 0
| it.span { _ => n += 1; n <= i }
| }}
defined class splitItAt
scala> val (is, rest) = (1 to 10).iterator.splitAt(6)
is: Iterator[Int] = non-empty iterator
rest: Iterator[Int] = unknown-if-empty iterator
scala> is.toList
res2: List[Int] = List(1, 2, 3, 4, 5, 6)
但我发现你确实想要使用前缀或剩余的迭代器。
我会写一个自定义方法。或者不要笑:
scala> val (is, rest) = (1 to 10).iterator.splitAt(6)
is: Iterator[Int] = non-empty iterator
rest: Iterator[Int] = unknown-if-empty iterator
scala> is match { case it: collection.Iterator$Leading$1 if rest.hasNext => it.finish() ; rest ; case _ => is }
res6: Iterator[Int] = unknown-if-empty iterator
scala> res6.next
res7: Int = 7
内部finish
表示您可以在不缓冲前缀的情况下使用rest
。
你也可以欺骗grouped
,并使用rest
的原始迭代器:
scala> val it = (1 to 10).iterator
it: Iterator[Int] = non-empty iterator
scala> val g = it.grouped(3)
g: it.GroupedIterator[Int] = non-empty iterator
scala> val first = g.next
first: List[Int] = List(1, 2, 3)
scala> it.hasNext
res12: Boolean = true
scala> it.next
res13: Int = 4
没有内部保留的自定义方法:
scala> :pa
// Entering paste mode (ctrl-D to finish)
implicit class splitItAt[A](private val it: Iterator[A]) extends AnyVal {
def splitAt(i: Int): (List[A], Iterator[A]) = {
val buf = mutable.ListBuffer.empty[A]
var n = 0
while (it.hasNext && n < i) {
buf += it.next()
n += 1
}
(buf.toList, it)
}
}
// Exiting paste mode, now interpreting.
defined class splitItAt
scala> val (is, rest) = (1 to 10).iterator.splitAt(20)
is: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
rest: Iterator[Int] = empty iterator
scala> val (is, rest) = (1 to 10).iterator.splitAt(6)
is: List[Int] = List(1, 2, 3, 4, 5, 6)
rest: Iterator[Int] = non-empty iterator
scala> val (is, rest) = (1 to 10).iterator.splitAt(0)
is: List[Int] = List()
rest: Iterator[Int] = non-empty iterator