Мне любопытно, если Scala имеет какой-то жемчуг, скрытый в классах коллекции, который я могу использовать. В основном я ищу что-то вроде очереди FIFO, но у этого есть верхний предел по его размеру, так что, когда предел поражен, самый старый (первый) элемент удаляется из очереди. Я реализовал это самостоятельно на Java в прошлом, но я предпочел бы использовать что-то стандартное, если это возможно.
Максимальная длина для очереди scala
Ответ 1
Чаще всего предпочтительной альтернативой подклассу является (к сожалению, названный) шаблон "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
s, включая те, которые создаются с помощью операций типа enqueue
, map
, ++
и т.д.
Обновить. Как говорит Дилан в комментариях, enqueueFinite
также необходимо взять параметр для максимального размера очереди и при необходимости удалить элементы. Я обновил код.
Ответ 2
Почему бы вам просто не подклассифицировать очередь FIFO? Что-то вроде этого должно работать: (псевдокод следует за...)
class Limited(limit:Int) extends FIFO {
override def enqueue() = {
if (size >= limit) {
//remove oldest element
}
super.enqueue()
}
}
Ответ 3
Вот неизменное решение:
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)