Maximum Length for scala queue

依然范特西╮ 提交于 2019-12-17 23:55:13

问题


I'm curious if Scala has some gem hidden in its collection classes that I can use. Basically I'm looking for something like a FIFO queue, but that has an upper-limit on its size such that when the limit is hit, the oldest (first) element is removed from the queue. I've implemented this myself in Java in the past, but I'd rather use something standard if possible.


回答1:


An often preferable alternative to subclassing is the (unfortunately named) "pimp my library" pattern. You can use it to add an enqueueFinite method to Queue, like so:

import scala.collection.immutable.Queue
class FiniteQueue[A](q: Queue[A]) {
  def enqueueFinite[B >: A](elem: B, maxSize: Int): Queue[B] = {
    var ret = q.enqueue(elem)
    while (ret.size > maxSize) { ret = ret.dequeue._2 }
    ret
  }
}
implicit def queue2finitequeue[A](q: Queue[A]) = new FiniteQueue[A](q)

Whenever queue2finitequeue is in scope, you can treat Queue objects as though they have the enqueueFinite method:

val maxSize = 3
val q1 = Queue(1, 2, 3)
val q2 = q1.enqueueFinite(5, maxSize)
val q3 = q2.map(_+1)
val q4 = q3.enqueueFinite(7, maxSize)

The advantage of this approach over subclassing is that enqueueFinite is available to all Queues, including those that are constructed via operations like enqueue, map, ++, etc.

Update: As Dylan says in the comments, enqueueFinite needs also to take a parameter for the maximum queue size, and drop elements as necessary. I updated the code.




回答2:


Why don't you just subclass a FIFO queue? Something like this should work: (pseudocode follows...)

class Limited(limit:Int) extends FIFO {
  override def enqueue() = {
    if (size >= limit) {
      //remove oldest element
    }
    super.enqueue()
  }
}



回答3:


Here is an immutable solution:

class FixedSizeFifo[T](val limit: Int)
( private val out: List[T], private val in: List[T] ) 
extends Traversable[T] {

  override def size = in.size + out.size

  def :+( t: T ) = {
    val (nextOut,nextIn) = if (size == limit) {
      if( out.nonEmpty) {
        ( out.tail, t::in ) 
      } else {
        ( in.reverse.tail, List(t) )
      }
    } else ( out, t::in )
      new FixedSizeFifo( limit )( nextOut, nextIn )
  }

  private lazy val deq = {
    if( out.isEmpty ) {
      val revIn = in.reverse
      ( revIn.head, new FixedSizeFifo( limit )( revIn.tail, List() ) )
    } else {
      ( out.head, new FixedSizeFifo( limit )( out.tail, in ) )
    }
  }
  override lazy val head = deq._1
  override lazy val tail = deq._2

  def foreach[U]( f: T => U ) = ( out ::: in.reverse ) foreach f

}

object FixedSizeFifo {
  def apply[T]( limit: Int ) = new FixedSizeFifo[T]( limit )(List(),List())
}

An example:

val fifo = FixedSizeFifo[Int](3) :+ 1 :+ 2 :+ 3 :+ 4 :+ 5 :+ 6
println( fifo )                //prints: FixedSizeFifo(4, 5, 6)
println( fifo.head )           //prints: 4
println( fifo.tail :+ 7 :+8 )  //prints: FixedSizeFifo(6, 7, 8)



回答4:


This is the approach I toke with extending Scala's standard mutable.Queue class.

class LimitedQueue[A](maxSize: Int) extends mutable.Queue[A] {
  override def +=(elem: A): this.type = {
    if (length >= maxSize) dequeue()
    appendElem(elem);
    this
  }
}

And simple use-case

var q2 = new LimitedQueue[Int](2)
q2 += 1
q2 += 2
q2 += 3
q2 += 4
q2 += 5

q2.foreach { n =>
  println(n)
}

You'll get only 4 and 5 in the console as the old elements were dequeued beforehand.



来源:https://stackoverflow.com/questions/6918731/maximum-length-for-scala-queue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!