Какова соответствующая коллекция для расчета среднего значения? - PullRequest
1 голос
/ 20 ноября 2010

Я просеиваю некоторые из моих старых ошибок и, просматривая какой-то неприятный код, я понял, что мой алгоритм усреднения или сглаживания был довольно плохим.Я провел небольшое исследование, которое привело меня к «среднему значению» - имеет смысл, довольно просто.Я размышлял над возможной реализацией и понял, что не знаю, какая коллекция обеспечит тот тип «скользящей» функциональности, которая мне нужна.Другими словами, мне нужно нажать / добавить элемент в конец коллекции, а затем также добавить / удалить первый элемент из коллекции.Я думаю, что если бы я знал, как это называется, я мог бы найти правильную коллекцию, но я не знаю, что искать.

В идеале это коллекция, в которой вы устанавливаете максимальный размер и все, что добавляется к нему, которое превышает этот размер.выскочил бы первый элемент.

Чтобы проиллюстрировать, вот что я придумал, пока возился:

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 ]

3 голосов
/ 20 ноября 2010

Похоже, вы ищете Круговой буфер .Вот реализация .NET в CodePlex.Вы также можете посмотреть на этот вопрос: Как бы вы кодировали эффективный кольцевой буфер в Java или C #?

Из предоставленного вами примера не ясно, как точно это относится к алгоритму среднего значения онлайн.Если единственная операция, разрешенная в буфере, это добавление;кеширование и обновление «итога» внутри буфера должно быть тривиально (добавьте новое значение, вычтите удаленное);сделав поддержание среднего значения O(1) операцией для каждого дополнения.В этом случае буфер эффективно удерживает Простое скользящее среднее (SMA) серии.

0 голосов
/ 20 ноября 2010

@ Ани - я создаю новый ответ вместо комментария, потому что у меня есть код для вставки.Я взмахнул простым мертвым объектом, чтобы помочь с моим средним значением, и придумал следующее:

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.Я перешел, должен вернуться к работе.Спасибо за помощь.

0 голосов
/ 20 ноября 2010

Список удовлетворяет вашим потребностям?

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

myList.Add("Something to the end");
myList.RemoveAt(0);
0 голосов
/ 20 ноября 2010

Вы смотрели на Класс очереди

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...