什么是计算运行平均值的合适集合?

时间:2010-11-20 07:27:33

标签: c# algorithm

我正在筛选一些旧的错误,在查看一些讨厌的代码时,我意识到我的平均或平滑算法非常糟糕。我做了一些研究,让我进入了"running mean" - 有道理,非常简单。我正在考虑一个可能的实现,并意识到我不知道哪个集合将提供我需要的“滑动”功能类型。换句话说,我需要将一个项目推送/添加到集合的末尾,然后弹出/删除集合中的第一个项目。我想如果我知道这叫什么,我可以找到正确的收藏品,但我不知道该搜索什么。

理想情况下,您设置最大尺寸的集合以及超出该尺寸的任何内容都会弹出第一个项目。

为了说明,这是我在弄乱的时候提出的:

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            LinkedList<int> samples = new LinkedList<int>();

            //  Simulate packing the front of the samples, this would most like be a pre-averaged
            //  value from the raw samples
            for (int i = 0; i < 10; i++)
            {
                samples.AddLast(0);
            }

            for (int i = 0; i < 100; i++)
            {
                //  My attempt at a "sliding collection" - not really sure what to call it but as
                //  an item is added the first item is removed
                samples.RemoveFirst();
                samples.AddLast(i);

                foreach (int v in samples)
                {
                    Console.Write("{0:000} ", v);
                }

                Console.WriteLine(String.Empty);
            }

            Console.ReadLine();
        }
    }
}

如您所见,我手动处理第一项的删除。我只是问是否有一个针对此类用途进行了优化的标准集合?

4 个答案:

答案 0 :(得分:3)

您似乎正在寻找Circular Buffer。这是CodePlex上的.NET implementation。您可能还想看看这个问题:How would you code an efficient Circular Buffer in Java or C#?

从您提供的示例中,不清楚完全如何与在线平均算法相关。如果缓冲区允许的唯一操作是追加;缓存和更新缓冲区内的“total”应该是微不足道的(添加新值,减去删除的值);为每个追加保持平均值O(1)操作。在这种情况下,缓冲区实际上保持了一系列的Simple Moving Average(SMA)。

答案 1 :(得分:0)

您是否看过Queue Class

答案 2 :(得分:0)

列表是否满足您的需求?

List<String> myList = new List<String>();

myList.Add("Something to the end");
myList.RemoveAt(0);

答案 3 :(得分:0)

@Ani - 我正在创建一个新的答案而不是评论,因为我有一些代码要粘贴。我对一个死的简单物体挥了挥手,以协助我的奔跑手段,并提出以下建议:

class RollingMean
{
    int _pos;
    int _count;
    double[] _buffer;

    public RollingMean(int size)
    {
        _buffer = new double[size];
        _pos = 0;
        _count = 0;
    }

    public RollingMean(int size, double initialValue) 
        : this(size)
    {
        //  Believe it or not there doesn't seem to be a better(performance) way...
        for (int i = 0; i < size; i++)
        {
            _buffer[i] = initialValue;
        }

        _count = size;
    }

    public double Push(double value)
    {
        _buffer[_pos] = value;

        _pos = (++_pos > _buffer.Length - 1) ? 0 : _pos;
        _count = Math.Min(++_count, _buffer.Length);

        return Mean;
    }

    public double Mean
    {
        get
        {
            return _buffer.Sum() / _count;
        }
    }
}

我正在从数据采集系统中读取16个数据通道,因此我将为每个通道实例化其中一个数据,我认为它比管理多维数组或每个缓冲区/帖子的单独一组更清晰信道。

以下是感兴趣的人的示例用法:

static void Main(string[] args)
{
    RollingMean mean = new RollingMean(10, 7);

    mean.Push(3);
    mean.Push(4);
    mean.Push(5);
    mean.Push(6);
    mean.Push(7.125);

    Console.WriteLine( mean.Mean );
    Console.ReadLine();
}

我打算将RollingMean对象设为通用而不是锁定为double,但是我找不到通用约束来限制tpye数值类型。我继续前进,得回去工作。谢谢你的帮助。