我很好奇Scala是否在我可以使用的集合类中隐藏了一些gem。基本上我正在寻找类似FIFO队列的东西,但是它的大小有一个上限,这样当命中限制时,最旧的(第一个)元素将从队列中删除。我过去曾用Java自己实现过,但如果可能的话,我宁愿使用标准的东西。
答案 0 :(得分:19)
子类化的一个常用的替代方法是(不幸命名的)“pimp my library”模式。您可以使用它将enqueueFinite
方法添加到Queue
,如下所示:
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)
只要queue2finitequeue
在范围内,您就可以将Queue
个对象视为拥有enqueueFinite
方法:
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)
此方法优于子类化的优势在于enqueueFinite
可用于所有Queue
,包括通过enqueue
,map
,{{等操作构建的++
1}}等等。
更新:正如Dylan在评论中所说,enqueueFinite
还需要获取最大队列大小的参数,并根据需要删除元素。我更新了代码。
答案 1 :(得分:4)
为什么不直接对FIFO队列进行子类化?这样的东西应该有效:(伪代码跟着......)
class Limited(limit:Int) extends FIFO {
override def enqueue() = {
if (size >= limit) {
//remove oldest element
}
super.enqueue()
}
}
答案 2 :(得分:4)
这是一个不可改变的解决方案:
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())
}
一个例子:
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)
答案 3 :(得分:0)
这是我扩展Scala的标准mutable.Queue类所采用的方法。
class LimitedQueue[A](maxSize: Int) extends mutable.Queue[A] {
override def +=(elem: A): this.type = {
if (length >= maxSize) dequeue()
appendElem(elem);
this
}
}
简单的用例
var q2 = new LimitedQueue[Int](2)
q2 += 1
q2 += 2
q2 += 3
q2 += 4
q2 += 5
q2.foreach { n =>
println(n)
}
由于旧元素已预先出队,您在控制台中只会看到4
和5
。