Как написать общее c скользящее среднее для списка элементов? - PullRequest
0 голосов
/ 20 апреля 2020

У меня есть класс в c#, объявленный как:

public class Item
{
    public double X { get; set; }
    public double Y { get; set; }
    public double XMovingAverage { get; set; }
    public double YMovingAverage { get; set; }
}

Предположим теперь, что у меня есть список таких предметов:

List<Item> items = <ordered list of items>

Тогда я мог бы вычислить перемещение среднее значение для X, например:

int index = 0;
foreach (var item in items)
{
    item.XMovingAverage = CalculateXMovingAverage(items, index, 100);
}

private double CalculateXMovingAverage(List<Item> items, int index, int N)
{
    double sum = 0.0;
    int i = index;
    int n = 0;
    while ((n < N) & (i >= 0))
    {
        sum += items[i].X;
        n++;
        i--;
    }

    double movingAverage = sum / n;

    return movingAverage;
}

Это отлично работает, но не очень элегантно, поскольку, если я хочу рассчитать скользящее среднее для Y, мне нужно снова скопировать / вставить точно такой же код для Y как я уже писал для X.

Как это можно сделать более элегантно, чтобы можно было рассчитать скользящее среднее для любого числового значения c для элементов в списке?

Ответы [ 3 ]

3 голосов
/ 20 апреля 2020

Я думаю, вы можете попробовать что-то вроде этого. Вам не нужны генерики, так как X и Y равны double. Я написал это без тестирования в IDE, но должно работать нормально.

int index = 0;
foreach (var item in items)
{
    item.XMovingAverage = CalculateMovingAverage(items, index, 100, item => item.X);
    item.YMovingAverage = CalculateMovingAverage(items, index, 100, item => item.Y);
}

private double CalculateMovingAverage(List<Item> items, int index, int N, Func<Item, double> selector)
{
    double sum = 0.0;
    int i = index;
    int n = 0;
    while ((n < N) & (i >= 0))
    {
        sum += selector(items[i]);
        n++;
        i--;
    }

    double movingAverage = sum / n;

    return movingAverage;
}

Надеюсь, это поможет.

2 голосов
/ 20 апреля 2020

Вы можете использовать Fun c, чтобы получить указатель на функцию, чтобы получить свойство для вычисления среднего значения.

private double CalculateMovingAverage<TItem>(IList<TItem> items, int index, int N, Func<TItem, int> func)
{
    double sum = 0.0;
    int i = index;
    int n = 0;
    while ((n < N) & (i >= 0))
    {
        sum += func(items[i]);
        n++;
        i--;
    }

    double movingAverage = sum / n;

    return movingAverage;
}

И можете вызывать его следующим образом:

int index = 0;
foreach (var item in items)
{
    item.XMovingAverage = CalculateMovingAverage(items, index, 100, (x) => x.X);
    item.XMovingAverage = CalculateMovingAverage(items, index, 100, (x) => x.Y);
}
0 голосов
/ 20 апреля 2020

В итоге я реализовал это как обобщенную c функцию, подобную этой (основываясь на ответах выше):

public static double SimpleMovingAverage<T>(List<T> items, int index, int N, Func<T, double> numberFunc)
{
    double sum = 0.0;
    int i = index;
    int n = 0;
    while ((n < N) & (i >= 0))
    {
        sum += numberFunc(items[i]);
        n++;
        i--;
    }

    double movingAverage = sum / n;

    return movingAverage;
}

Я также создал функцию для экспоненциальной скользящей средней:

public static double ExponentialMovingAverage<T>(List<T> items, int index, int N, Func<T, double> numberFunc)
{
    int n = Math.Min(index + 1, N); // May have to use smaller series in the beginning

    double k = 2.0 / (n + 1.0);

    double currentEMA = SimpleMovingAverage<T>(items, index, N, numberFunc); // Use Simple Moving Average as the starting point

    int start = index - n + 1;
    for (int i = 0; i < n; i++)
    {
        double previousEMA = currentEMA;
        double value = numberFunc(items[start + i]);
        currentEMA = (value * k) + previousEMA * (1.0 - k);
    }

    return currentEMA;
}

Теперь я могу использовать их в многократно используемой библиотеке для разных типов списков и для любых двойных значений в элементах.

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