collections - Begrenzen Sie die Größe der Warteschlange <T> in .NET?

Translate

Ich habe ein Queue <T> -Objekt, das ich auf eine Kapazität von 2 initialisiert habe, aber das ist natürlich nur die Kapazität und es wird ständig erweitert, wenn ich Elemente hinzufüge. Gibt es bereits ein Objekt, das ein Element automatisch aus der Warteschlange entfernt, wenn das Limit erreicht ist, oder ist dies die beste Lösung, um meine eigene geerbte Klasse zu erstellen?

This question and all comments follow the "Attribution Required."

Alle Antworten

Translate

Ich habe eine Basisversion von dem, wonach ich suche, zusammengestellt. Sie ist nicht perfekt, aber sie erledigt den Job, bis etwas Besseres eintritt.

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);
    }
}
Quelle
Translate

Ich würde empfehlen, dass Sie die ziehenC5 Bibliothek. Im Gegensatz zu SCG (System.Collections.Generic) ist C5 als Schnittstelle programmiert und für die Unterklasse ausgelegt. Die meisten öffentlichen Methoden sind virtuell und keine der Klassen ist versiegelt. Auf diese Weise müssen Sie nicht das icky "neue" Schlüsselwort verwenden, das nicht ausgelöst würde, wenn IhrLimitedQueue<T>wurden zu einem gegossenSCG.Queue<T>. Mit C5 und der Verwendung nahezu des gleichen Codes wie zuvor würden Sie von der ableitenCircularQueue<T>. DasCircularQueue<T>Implementiert tatsächlich sowohl einen Stapel als auch eine Warteschlange, sodass Sie beide Optionen mit einem Limit fast kostenlos erhalten können. Ich habe es unten mit einigen 3.5 Konstrukten umgeschrieben:

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

Ich denke, dass dieser Code genau das tun sollte, wonach Sie gesucht haben.

Quelle
Translate

Sie sollten Ihre eigene Klasse erstellen, ein Ringpuffer würde wahrscheinlich Ihren Anforderungen entsprechen.

Die Datenstrukturen in .NET, mit denen Sie die Kapazität mit Ausnahme des Arrays angeben können, verwenden diese, um die interne Datenstruktur zu erstellen, die zum Speichern der internen Daten verwendet wird.

Beispielsweise wird für eine Liste die Kapazität verwendet, um die Größe eines internen Arrays zu bestimmen. Wenn Sie anfangen, Elemente zur Liste hinzuzufügen, wird dieses Array ab Index 0 gefüllt. Wenn es Ihre Kapazität erreicht, erhöht es die Kapazität auf eine neue höhere Kapazität und füllt es weiter.

Quelle
Translate

Warum würden Sie nicht einfach ein Array mit einer Größe von 2 verwenden? Eine Warteschlange soll dynamisch wachsen und schrumpfen können.

Oder erstellen Sie eine Wrapper-Klasse um eine Instanz vonQueue<T>Instanz und jedes Mal, wenn man a in die Warteschlange stellt<T>Objekt, überprüfen Sie die Größe der Warteschlange. Wenn größer als 2, entfernen Sie das erste Element aus der Warteschlange.

Quelle
Translate

Nun, ich hoffe, dieser Kurs hilft Ihnen:
Intern verwendet der zirkuläre FIFO-Puffer eine Warteschlange <T> mit der angegebenen Größe. Sobald die Größe des Puffers erreicht ist, werden ältere Elemente durch neue ersetzt.

HINWEIS: Sie können Elemente nicht zufällig entfernen. Ich habe die Methode Remove (T item) so eingestellt, dass false zurückgegeben wird. Wenn Sie möchten Sie können Änderungen vornehmen, um Elemente nach dem Zufallsprinzip zu entfernen

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
}
Quelle
Translate

Gleichzeitige Lösung

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

Hinweis: SeitEnqueueSteuert das Hinzufügen von Elementen und tut dies nacheinander. Es ist nicht erforderlich, a auszuführenwhilezumTryDequeue.

Quelle
Translate

Wenn es für irgendjemanden von Nutzen ist, habe ich eine gemachtLimitedStack<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; }
    }
}

Es entfernt den ältesten Gegenstand (Boden des Stapels), wenn er zu groß wird.

(Diese Frage war das beste Google-Ergebnis für "C # Limit Stack Size".)

Quelle