Reputation: 44376
I have what I would think is the most common case for processing a queue. I will read off the front of the queue, act on the element (which may cause more elements to be added to the queue), and then loop until the queue is empty.
foreach
, but no, apparently a queue (even a mutable one) is strict and the foreach loops over all the elements that are in the queue when the iteration starts.while
loop.You'd think that it would be something like
while (!q.isEmpty) {
var (e, q) = q.dequeue
... }
would work, except that I'm redeclaring q
. This does work:
while (!q.isEmpty) {
var (e, q1) = q.dequeue
q = q1
... }
but man, does it look wrong ...
Upvotes: 28
Views: 9645
Reputation: 382
Processing a Queue
in a while
loop can be done without a duplicate var
/val
as follows:
var q = Queue("foo", "bar", "baz")
while (q.nonEmpty) {
val e = q.head
q = q.tail
// Do something with `e` here
}
(I am aware that this answer is 7 years late, but I thought it a valuable alternative nonetheless.)
Upvotes: 9
Reputation: 297155
While Rex Kerr's answer is good, iterators are mutable. Here's a truly immutable solution, modeled very closely on the code in Rex Kerr's own answer.
val q0 = collection.immutable.Queue("1","Two","iii")
@annotation.tailrec def processQueue(queue: collection.immutable.Queue[String]): Unit = if (queue.nonEmpty) {
val (element, rest) = queue.dequeue
println("I just dequeued "+element)
if (element.length != 2) processQueue(rest.enqueue(".."))
else processQueue(rest)
}
processQueue(q0)
Upvotes: 14
Reputation: 167871
Here's one way to avoid any vars at all:
val q0 = collection.immutable.Queue("1","Two","iii")
Iterator.iterate(q0) { qi =>
val (e,q) = qi.dequeue
println("I just dequeued "+e) // Your side-effecting operations go here
if (e.length!=2) q.enqueue("..") // Your changes to the queue go here
else q
}.takeWhile(! _.isEmpty).foreach(identity)
You start with the initial queue, q0
, and then on the qi
th step, you dequeue something and produce a new queue if need be, returning that for the next step.
All you have left is the stopping condition (not empty), and then since this just defines a process, not the actual action, you have to run it (using a no-op foreach, for example).
Upvotes: 17