Limit Größe der Queue <T> in .NET?

stimmen
50

Ich habe eine Queue <T> Objekt, das ich auf eine Kapazität von 2 initialisiert habe, aber offensichtlich, dass nur die Kapazität und es hält erweitert, wie ich Elemente hinzuzufügen. Gibt es bereits ein Objekt, das ein Element automatisch aus der Warteschlange entfernt, wenn die Grenze erreicht ist, oder ist die beste Lösung, meine eigene vererbten Klasse zu erstellen?

Veröffentlicht am 04/08/2008 um 15:47
quelle vom benutzer
In anderen Sprachen...                            


7 antworten

stimmen
32

Ich habe eine Basisversion von oben geklopft, was ich suche, ist es nicht perfekt, aber es wird die Arbeit erledigen, bis etwas Besseres kommt.

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);
    }
}
Beantwortet am 04/08/2008 um 15:57
quelle vom benutzer

stimmen
17

Ich würde empfehlen , dass Sie die Pull - up - C5 - Bibliothek . Im Gegensatz zu SCG (System.Collections.Generic) wird C5 - Schnittstelle programmiert und werden subclassed gestaltet. Die meisten öffentlichen Methoden sind virtuelle und keine der Klassen abgedichtet sind. Auf diese Weise werden Sie nicht , dass icky „neuen“ Schlüsselwort verwenden müssen , die nicht auslösen würde , wenn Ihr LimitedQueue<T>auf eine gegossen wurden SCG.Queue<T>. Mit C5 und mit der Nähe zu den gleichen Code wie zuvor hätten, würden Sie von der ableiten CircularQueue<T>. Die CircularQueue<T>implementiert tatsächlich sowohl einen Stapels und eine Warteschlange, so dass Sie beiden Optionen mit einem Limit kostenlos fast bekommen. Ich habe es neu geschrieben unten mit einigen 3,5 - Konstrukten:

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 sollte genau das tun, was Sie suchen.

Beantwortet am 24/10/2008 um 14:51
quelle vom benutzer

stimmen
5

Sie sollten Ihre eigene Klasse erstellen, wird ein Ringpuffer würde wahrscheinlich Ihre Bedürfnisse anzupassen.

Die Datenstrukturen in .NET, die Sie Kapazität, mit Ausnahme von Array angeben können, verwenden diese die interne Datenstruktur zu bauen verwendet, um die internen Daten zu halten.

Zum Beispiel für eine Liste ist, Kapazität zu Größe ein internes Array verwendet. Beim Starten Elemente zur Liste hinzufügen, wird es beginnen dieses Array aus dem Index Füllung 0 und höher, und wenn es Ihre Kapazität erreicht, erhöht sich die Kapazität auf eine neue höhere Kapazität, und setzt es füllt.

Beantwortet am 04/08/2008 um 15:56
quelle vom benutzer

stimmen
3

Nun , ich hoffe , dass diese Klasse Wille hilft Ihnen:
Intern wird der Rund FIFO - Puffer eine Queue verwenden <T> mit der angegebenen Größe. Sobald die Größe des Puffers erreicht ist, wird es ältere Elemente durch neue ersetzt.

Hinweis: Sie können keine Elemente zufällig entfernen. Ich habe die Methode Remove (T), um falsch zurück. wenn Sie möchten, können Sie ändern Objekte zufällig 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
}
Beantwortet am 15/11/2011 um 13:40
quelle vom benutzer

stimmen
3

Warum würden Sie nicht nur ein Array mit einer Größe von 2 verwenden? Ein Queue soll in der Lage sein, dynamisch zu wachsen und schrumpfen.

Oder eine Wrapper - Klasse um eine Instanz erstellen Queue<T>Instanz und jedes Mal , wenn eine Enqueues ein <T>Objekt, überprüfen die Größe der Warteschlange. Wenn größer als 2 ist , aus der Warteschlange entfernt das erste Element.

Beantwortet am 04/08/2008 um 15:52
quelle vom benutzer

stimmen
1

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

Es entfernt den ältesten Artikel (unten im Stapel), wenn es zu groß wird.

(Diese Frage war das Top-Google-Ergebnis für „C # Limit Stapelgröße“)

Beantwortet am 15/01/2012 um 06:28
quelle vom benutzer

stimmen
0

Concurrent-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: Da Enqueuesteuert die Zugabe von Elementen, und zwar einen nach dem anderen, gibt es keine Notwendigkeit zur Ausführung eines whilefür TryDequeue.

Beantwortet am 09/05/2018 um 20:39
quelle vom benutzer

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