2011-08-02 21 views
12

Tengo curiosidad si Scala tiene alguna gema escondida en sus clases de colección que puedo usar. Básicamente, estoy buscando algo así como una cola FIFO, pero que tiene un límite superior en su tamaño, de modo que cuando se alcanza el límite, el elemento más antiguo (primero) se elimina de la cola. Ya lo implementé en Java en el pasado, pero preferiría usar algo estándar si fuera posible.Longitud máxima para la cola de scala

Respuesta

19

Una alternativa preferible a menudo subclases es el (mal llamada) patrón "pimp my library". Se puede utilizar para agregar un método enqueueFinite a Queue, así:

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) 

Siempre queue2finitequeue es en su alcance, se puede tratar Queue objetos como si tuvieran la enqueueFinite método:

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) 

La ventaja de este enfoque sobre la subclasificación es que enqueueFinite está disponible para todos Queue s, incluidos los que se construyen mediante operaciones como enqueue, map, ++, etc.

Actualización: Como dice Dylan en los comentarios, enqueueFinite también necesita tomar un parámetro para el tamaño máximo de cola, y soltar elementos según sea necesario. Actualicé el código.

+0

Cool. ¿Pero cómo se supera el tamaño máximo de cola? – paradigmatic

+0

Veo dos opciones: su cola finita es mutable, en cuyo caso puede cambiar el tamaño después de su creación (eliminando elementos si es necesario), o su cola es inmutable, en cuyo caso agregaría el límite al método 'enqueueFinite'. – Dylan

+0

o puede agregar un parámetro 'Int' implícito. – Jus12

4

¿Por qué no solo subclase una cola FIFO? Algo como esto debería funcionar: (pseudocódigo sigue ...)

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

Otra opción es utilizar el patrón de "Pimp mi biblioteca" para añadir un método 'enqueueFinite' a la clase de cola. Esto parece preferible porque evita los problemas de tipo con los métodos habituales ('map',' ++ ', ...) –

+0

@Kipton debe hacer su propia respuesta. Creo que es realmente preferible de hecho. –

+0

Hecho, gracias por la sugerencia. –

4

Aquí es una solución inmutable:

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()) 
} 

Un ejemplo:

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) 
Cuestiones relacionadas