Maximum Length for scala queue

后端 未结 4 1472
死守一世寂寞
死守一世寂寞 2020-12-09 04:55

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 i

相关标签:
4条回答
  • 2020-12-09 04:56

    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.

    0 讨论(0)
  • 2020-12-09 04:59

    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()
      }
    }
    
    0 讨论(0)
  • 2020-12-09 05:12

    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)
    
    0 讨论(0)
  • 2020-12-09 05:17

    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.

    0 讨论(0)
提交回复
热议问题