I want to take an
immutable Array, for example.
val arr = Array(3, 7, 2)
|
I want a method to get
the next element in the Array. But, I
want it to reset the index after it reads the last element in the Array.
I could do this
val arr = Array(3, 7, 2)
val itr = arr.iterator println(itr.next) println(itr.next) println(itr.next) |
And I would get back
this.
3
7
2
|
But if I call .next one
more time I get a NoSuchElement Exception, as the iterator runs out.
Iterators are designed
to run through the list, they can't be reset.
See http://stackoverflow.com/questions/5159000/stream-vs-views-vs-iterators [1] and http://stackoverflow.com/questions/5159000/stream-vs-views-vs-iterators [2]
What about using a
Stream to solve my problem?
Stream solution
What if I made an infinite stream that gives me the next
index I want. For example, if I have an
Array of length 3 I want the stream to output
0, 1, 2, 0, 1, 2, 0, 1, 2……
Here is a bit of code that does that (well gets the index as
a Stream)
val arr = Array(3, 7, 2) lazy val s1: Stream[Int] = 0 #:: s1.map(n => (n+1) % arr.length) println(s1.take(10).toList) |
Here is the output
List(0, 1, 2, 0, 1, 2, 0, 1, 2, 0) |
That gives me the sequence I want. But there is one problem with the stream as
is.
Memoization! As is it keeps track of all the values of
the stream.
Here is some code that test this (Causes an out of memory
error)
val arr = Array(3, 7, 2)
//This runs of of
memory if I set memory to -Xmx64m -Xms64m
lazy val s1: Stream[Int] = 0 #:: s1.map(n => (n+1) % arr.length) println("Last " + s1.drop(100e6.toInt).take(1).toList) |
(I also reduced my memory)
In Intellij I set it to 64MiB and ran it.
Out of Memory!
There is simple way around this.
Stream to Iterator
This code fixes my memoization problem
val arr = Array(3, 7, 2) val index:Iterator[Int] = Stream.iterate(0)(i => (i+1)%arr.length).iterator println(index.take(10).toList) println(index.next) println(index.next) println(index.next)
println(index.next)
println(index.next) println("No Memoization " + index.drop(100e6.toInt).next) println(index.next) println(index.next) println(index.next) |
Here is the output
Now let me update my code just to show it is getting the correct
results from the array.
val arr = Array(3, 7, 2) val index:Iterator[Int] = Stream.iterate(0)(i => (i+1)%arr.length).iterator println(arr(index.next)) println(arr(index.next)) println(arr(index.next)) println(arr(index.next)) println(arr(index.next)) println(arr(index.next)) println(arr(index.next)) |
And here is my output.
That is working the way I want it to J.
Maybe there is a better way to do this but for now this
works and does not give me the Memoization memory leak.
References
[1] Stream vs Views vs Iterators http://stackoverflow.com/questions/5159000/stream-vs-views-vs-iterators
Accessed 02/2016
[2] Why iterator doesn't have
any reset method? http://stackoverflow.com/questions/7689261/why-iterator-doesnt-have-any-reset-method
Accessed 06/2014
No comments:
Post a Comment