Limitar tamanho do Queue <T> em .NET?

votos
50

Eu tenho um objeto Queue <T> que eu inicializado para uma capacidade de 2, mas, obviamente, isso é apenas a capacidade e continua em expansão como eu adicionar itens. Já existe um objeto que dequeues um item automaticamente quando o limite for atingido, ou é a melhor solução para criar minha própria classe herdada?

Publicado 04/08/2008 em 15:47
fonte usuário
Em outras línguas...                            


7 respostas

votos
32

Eu bati uma versão básica do que eu estou procurando, não é perfeito, mas ele vai fazer o trabalho até que algo melhor vem junto.

public class LimitedQueue<T> : Queue<T>
{
    public int Limit { get; set; }

    public LimitedQueue(int limit) : base(limit)
    {
        Limit = limit;
    }

    public new void Enqueue(T item)
    {
        while (Count >= Limit)
        {
            Dequeue();
        }
        base.Enqueue(item);
    }
}
Respondeu 04/08/2008 em 15:57
fonte usuário

votos
17

Eu recomendaria que você puxar para cima a Biblioteca C5 . Ao contrário de SCG (System.Collections.Generic), C5 é programado para interface e concebido para ser uma subclasse. A maioria dos métodos públicos são virtuais e nenhuma das classes estão selados. Dessa forma, você não terá que usar essa nojenta "nova" palavra-chave que não provocaria se o seu LimitedQueue<T>foram lançados a uma SCG.Queue<T>. Com C5 e usando perto do mesmo código que você tinha antes, você iria derivar da CircularQueue<T>. O CircularQueue<T>realmente implementa tanto uma pilha e uma fila, para que possa obter as duas opções com limite quase de graça. Eu reescrito-lo abaixo com cerca de 3,5 construções:

using C5;

public class LimitedQueue<T> : CircularQueue<T>
{
    public int Limit { get; set; }

    public LimitedQueue(int limit) : base(limit)
    {
        this.Limit = limit;
    }

    public override void Push(T item)
    {
        CheckLimit(false);
        base.Push(item);
    }

    public override void Enqueue(T item)
    {
        CheckLimit(true);
        base.Enqueue(item);
    }

    protected virtual void CheckLimit(bool enqueue)
    {
        while (this.Count >= this.Limit)
        {
            if (enqueue)
            {
                this.Dequeue();
            }
            else
            {
                this.Pop();
            }
        }
    }
}

Eu acho que este código deve fazer exatamente o que você estava procurando.

Respondeu 24/10/2008 em 14:51
fonte usuário

votos
5

Você deve criar sua própria classe, uma memia tamp circular, provavelmente, atender às suas necessidades.

As estruturas de dados em .NET que permite que você especifique a capacidade, exceto matriz, usa isso para construir a estrutura de dados interna utilizada para armazenar os dados internos.

Por exemplo, para obter uma lista, a capacidade é usada para o tamanho de uma matriz interna. Quando você começar a adicionar elementos à lista, ele vai começar a preencher essa matriz de índice 0 e para cima, e quando atinge o seu capacidade, aumenta a capacidade de uma nova capacidade mais elevada, e continua enchendo-o.

Respondeu 04/08/2008 em 15:56
fonte usuário

votos
3

Bem, espero que esta classe irá ajuda-lo:
Internamente, o FIFO buffer circular usar uma fila <T> com o tamanho especificado. Uma vez que o tamanho do buffer é atingido, ele irá substitui os itens mais antigos com novos.

NOTA: Você não pode remover itens aleatoriamente. Eu defini o método Remove (ponto T) para retornar falso. Se você quiser, pode modificar para remover itens aleatoriamente

public class CircularFIFO<T> : ICollection<T> , IDisposable
{
    public Queue<T> CircularBuffer;

    /// <summary>
    /// The default initial capacity.
    /// </summary>
    private int capacity = 32;

    /// <summary>
    /// Gets the actual capacity of the FIFO.
    /// </summary>
    public int Capacity
    {
        get { return capacity; }          
    }

    /// <summary>
    ///  Initialize a new instance of FIFO class that is empty and has the default initial capacity.
    /// </summary>
    public CircularFIFO()
    {            
        CircularBuffer = new Queue<T>();
    }

    /// <summary>
    /// Initialize a new instance of FIFO class that is empty and has the specified initial capacity.
    /// </summary>
    /// <param name="size"> Initial capacity of the FIFO. </param>
    public CircularFIFO(int size)
    {
        capacity = size;
        CircularBuffer = new Queue<T>(capacity);
    }

    /// <summary>
    /// Adds an item to the end of the FIFO.
    /// </summary>
    /// <param name="item"> The item to add to the end of the FIFO. </param>
    public void Add(T item)
    {
        if (this.Count >= this.Capacity)
            Remove();

        CircularBuffer.Enqueue(item);
    }

    /// <summary>
    /// Adds array of items to the end of the FIFO.
    /// </summary>
    /// <param name="item"> The array of items to add to the end of the FIFO. </param>
     public void Add(T[] item)
    { 
        int enqueuedSize = 0;
        int remainEnqueueSize = this.Capacity - this.Count;

        for (; (enqueuedSize < item.Length && enqueuedSize < remainEnqueueSize); enqueuedSize++)
            CircularBuffer.Enqueue(item[enqueuedSize]);

        if ((item.Length - enqueuedSize) != 0)
        {
            Remove((item.Length - enqueuedSize));//remaining item size

            for (; enqueuedSize < item.Length; enqueuedSize++)
                CircularBuffer.Enqueue(item[enqueuedSize]);
        }           
    }

    /// <summary>
    /// Removes and Returns an item from the FIFO.
    /// </summary>
    /// <returns> Item removed. </returns>
    public T Remove()
    {
        T removedItem = CircularBuffer.Peek();
        CircularBuffer.Dequeue();

        return removedItem;
    }

    /// <summary>
    /// Removes and Returns the array of items form the FIFO.
    /// </summary>
    /// <param name="size"> The size of item to be removed from the FIFO. </param>
    /// <returns> Removed array of items </returns>
    public T[] Remove(int size)
    {
        if (size > CircularBuffer.Count)
            size = CircularBuffer.Count;

        T[] removedItems = new T[size];

        for (int i = 0; i < size; i++)
        {
            removedItems[i] = CircularBuffer.Peek();
            CircularBuffer.Dequeue();
        }

        return removedItems;
    }

    /// <summary>
    /// Returns the item at the beginning of the FIFO with out removing it.
    /// </summary>
    /// <returns> Item Peeked. </returns>
    public T Peek()
    {
        return CircularBuffer.Peek();
    }

    /// <summary>
    /// Returns the array of item at the beginning of the FIFO with out removing it.
    /// </summary>
    /// <param name="size"> The size of the array items. </param>
    /// <returns> Array of peeked items. </returns>
    public T[] Peek(int size)
    {
        T[] arrayItems = new T[CircularBuffer.Count];
        CircularBuffer.CopyTo(arrayItems, 0);

        if (size > CircularBuffer.Count)
            size = CircularBuffer.Count;

        T[] peekedItems = new T[size];

        Array.Copy(arrayItems, 0, peekedItems, 0, size);

        return peekedItems;
    }

    /// <summary>
    /// Gets the actual number of items presented in the FIFO.
    /// </summary>
    public int Count
    {
        get
        {
            return CircularBuffer.Count;
        }
    }

    /// <summary>
    /// Removes all the contents of the FIFO.
    /// </summary>
    public void Clear()
    {
        CircularBuffer.Clear();
    }

    /// <summary>
    /// Resets and Initialize the instance of FIFO class that is empty and has the default initial capacity.
    /// </summary>
    public void Reset()
    {
        Dispose();
        CircularBuffer = new Queue<T>(capacity);
    }

    #region ICollection<T> Members

    /// <summary>
    /// Determines whether an element is in the FIFO.
    /// </summary>
    /// <param name="item"> The item to locate in the FIFO. </param>
    /// <returns></returns>
    public bool Contains(T item)
    {
        return CircularBuffer.Contains(item);
    }

    /// <summary>
    /// Copies the FIFO elements to an existing one-dimensional array. 
    /// </summary>
    /// <param name="array"> The one-dimensional array that have at list a size of the FIFO </param>
    /// <param name="arrayIndex"></param>
    public void CopyTo(T[] array, int arrayIndex)
    {
        if (array.Length >= CircularBuffer.Count)
            CircularBuffer.CopyTo(array, 0);           
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

    public bool Remove(T item)
    {
        return false; 
    }

    #endregion

    #region IEnumerable<T> Members

    public IEnumerator<T> GetEnumerator()
    {
       return CircularBuffer.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    IEnumerator IEnumerable.GetEnumerator()
    {
        return CircularBuffer.GetEnumerator();
    }

    #endregion

    #region IDisposable Members

    /// <summary>
    /// Releases all the resource used by the FIFO.
    /// </summary>
    public void Dispose()
    {          
        CircularBuffer.Clear();
        CircularBuffer = null;
        GC.Collect();
    }

    #endregion
}
Respondeu 15/11/2011 em 13:40
fonte usuário

votos
3

Por que você não apenas usar uma matriz com um tamanho de 2? A fila é suposto ser capaz de crescer de forma dinâmica e encolher.

Ou criar uma classe de invólucro em torno de uma instância de Queue<T>instância e cada vez que um enfileira um <T>objeto, verificar o tamanho da fila. Se for maior do que 2, desenfileirar o primeiro item.

Respondeu 04/08/2008 em 15:52
fonte usuário

votos
1

Se é de alguma utilidade para ninguém, eu fiz um LimitedStack<T>.

public class LimitedStack<T>
{
    public readonly int Limit;
    private readonly List<T> _stack;

    public LimitedStack(int limit = 32)
    {
        Limit = limit;
        _stack = new List<T>(limit);
    }

    public void Push(T item)
    {
        if (_stack.Count == Limit) _stack.RemoveAt(0);
        _stack.Add(item);
    }

    public T Peek()
    {
        return _stack[_stack.Count - 1];
    }

    public void Pop()
    {
        _stack.RemoveAt(_stack.Count - 1);
    }

    public int Count
    {
        get { return _stack.Count; }
    }
}

Ele remove o item mais antigo (parte inferior da pilha) quando fica muito grande.

(Esta pergunta foi o primeiro resultado no Google por "C tamanho da pilha limite #")

Respondeu 15/01/2012 em 06:28
fonte usuário

votos
0

Solução Concurrent

public class LimitedConcurrentQueue<ELEMENT> : ConcurrentQueue<ELEMENT>
{
    public readonly int Limit;

    public LimitedConcurrentQueue(int limit)
    {
        Limit = limit;
    }

    public new void Enqueue(ELEMENT element)
    {
        base.Enqueue(element);
        if (Count > Limit)
        {
            TryDequeue(out ELEMENT discard);
        }
    }
}

Nota: Uma vez que Enqueuecontrola a adição de elementos, e fá-lo um de cada vez, não há necessidade de executar um whilepara TryDequeue.

Respondeu 09/05/2018 em 20:39
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more