Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 328
JYelton Avatar asked Jun 17 '11 22:06

JYelton


2 Answers

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.

like image 144
Thomas Levesque Avatar answered Sep 27 '22 01:09

Thomas Levesque


private int ct = 0;
private long[] times = new long[10];

void DoStuff ()
{
   ...
   times[ct] = MyStopWatch.ElapsedMilliseconds;
   ct = (ct + 1) % times.Length; // Wrap back around to 0 when we reach the end.
}

Here is a simple circular structure. This requires none of the array copying or garbage collection of linked list nodes that the other solutions have.

like image 26
agent-j Avatar answered Sep 24 '22 01:09

agent-j