Search code examples
c#collectionscircular-buffer

How do I keep a list of only the last n objects?


I want to do some performance measuring of a particular method, but I'd like to average the time it takes to complete. (This is a C# Winforms application, but this question could well apply to other frameworks.)

I have a Stopwatch which I reset at the start of the method and stop at the end. I'd like to store the last 10 values in a list or array. Each new value added should push the oldest value off the list.

Periodically I will call another method which will average all stored values.

Am I correct in thinking that this construct is a circular buffer?

How can I create such a buffer with optimal performance? Right now I have the following:

List<long> PerfTimes = new List<long>(10);

// ...

private void DoStuff()
{
    MyStopWatch.Restart();
    // ...
    MyStopWatch.Stop();
    PerfTimes.Add(MyStopWatch.ElapsedMilliseconds);
    if (PerfTimes.Count > 10) PerfTimes.RemoveAt(0);
}

This seems inefficient somehow, but perhaps it's not.

Suggestions?


Solution

  • You could create a custom collection:

    class SlidingBuffer<T> : IEnumerable<T>
    {
        private readonly Queue<T> _queue;
        private readonly int _maxCount;
    
        public SlidingBuffer(int maxCount)
        {
            _maxCount = maxCount;
            _queue = new Queue<T>(maxCount);
        }
    
        public void Add(T item)
        {
            if (_queue.Count == _maxCount)
                _queue.Dequeue();
            _queue.Enqueue(item);
        }
    
        public IEnumerator<T> GetEnumerator()
        {
            return _queue.GetEnumerator();
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
    

    Your current solution works, but it's inefficient, because removing the first item of a List<T> is expensive.