Вопрос

Я разрабатываю простую внутреннюю структуру для обработки данных временных рядов. Учитывая, что LINQ - мой текущий игрушечный молоток, я хочу ударить по нему всем.

Я хочу реализовать методы в классе TimeSeries (Select (), Where () и т. д.), чтобы я мог использовать синтаксис LINQ для обработки данных временных рядов

Некоторые вещи просты, например, (из x в A выберите x + 10), давая новый временной ряд.

Каков наилучший дизайн синтаксиса для объединения двух или более временных рядов? (из a в A из b в B выберите a + b) не велико, поскольку оно выражает вложенный цикл. Может быть, некоторые присоединиться? Это должно соответствовать присоединению к неявной переменной времени. (То, что я имею в виду, соответствует функции lisp 'zip')

<Ч>

РЕДАКТИРОВАТЬ: Требуются некоторые пояснения.

Временной ряд - это функция, зависящая от времени, например, котировки акций. Комбинация временных рядов может представлять собой разницу между двумя ценами на акции как функцию времени.

Stock1.MyJoin(Stock2, (a,b)=>a-b)

возможно, но можно ли это выразить аккуратно, используя некоторый синтаксис LINQ? Я ожидаю реализовать методы LINQ в классе MyTimeSeries .

Это было полезно?

Решение

Если я правильно понимаю вопрос, вы хотите объединить несколько последовательностей на основе их положения в последовательности?

В классе System.Linq.Enumerable нет ничего, что могло бы сделать это, поскольку методы Join и GroupJoin основаны на соединить ключи. Однако, по стечению обстоятельств, я написал метод PositionalJoin для этой цели несколько дней назад, используемый как в вашем примере:

sequenceA.PositionalJoin(sequenceB, (a, b) => new { a, b });

Семантика метода, показанного ниже, состоит в том, что он не требует, чтобы последовательности были одинаковой длины, но было бы тривиально изменить его, чтобы потребовать этого. Я также прокомментировал, где должна быть проверка аргументов, как это было с использованием наших внутренних вспомогательных классов.

public static IEnumerable<TResult> PositionalJoin<T1, T2, TResult>(
    this IEnumerable<T1> source1, 
    IEnumerable<T2> source2, 
    Func<T1, T2, int, TResult> selector)
{
    // argument checking here
    return PositionalJoinIterator(source1, source2, selector);
}

private static IEnumerable<TResult> PositionalJoinIterator<T1, T2, TResult>(
    IEnumerable<T1> source1, 
    IEnumerable<T2> source2, 
    Func<T1, T2, TResult> selector)
{
    using (var enumerator1 = source1.GetEnumerator())
    using (var enumerator2 = source2.GetEnumerator())
    {
        bool gotItem;
        do
        {
            gotItem = false;

            T1 item1;
            if (enumerator1.MoveNext())
            {
                item1 = enumerator1.Current;
                gotItem = true;
            }
            else
            {
                item1 = default(T1);
            }

            T2 item2;
            if (enumerator2.MoveNext())
            {
                item2 = enumerator2.Current;
                gotItem = true;
            }
            else
            {
                item2 = default(T2);
            }

            if (gotItem)
            {
                yield return selector(item1, item2);
            }
        }
        while (gotItem);
    }
}

Не уверен, что это именно то, что вам нужно, но, надеюсь, вам поможет.

Другие советы

Union звучит как правильный путь - нет поддержки выражений запросов, но я думаю, что это выражает то, что вы имеете в виду.

Возможно, вам будет интересно посмотреть классы на основе Range в MiscUtil , которые могут быть хорошо использованным для времен. В сочетании с небольшим удовольствием от метода расширения, вы можете сделать:

foreach (DateTime day in 19.June(1976).To(DateTime.Today).Step(1.Day()))
{
    Console.WriteLine("I'm alive!");
}

Я не предлагаю, чтобы это заменило то, что вы делаете, просто чтобы вы могли принять некоторые идеи, чтобы сделать это еще лучше. Не стесняйтесь вносить свой вклад тоже:)

Из моего проекта NExtension :

public static IEnumerable<TResult> Zip<T1, T2, TResult>(
    this IEnumerable<T1> source1, 
    IEnumerable<T2> source2, 
    Func<T1, T2, TResult> combine)
{
    if (source1 == null)
        throw new ArgumentNullException("source1");
    if (source2 == null)
        throw new ArgumentNullException("source2");
    if (combine == null)
        throw new ArgumentNullException("combine");

    IEnumerator<T1> data1 = source1.GetEnumerator();
    IEnumerator<T2> data2 = source2.GetEnumerator();
    while (data1.MoveNext() && data2.MoveNext())
    {
        yield return combine(data1.Current, data2.Current);
    }
}

Синтаксис:

Stock1.Zip(Stock2, (a,b)=>a-b)

Бьярке, взгляните на NEsper, это приложение для комплексной обработки событий с открытым исходным кодом, которое, помимо прочего, выполняет запросы временных рядов, подобные SQL. Вы можете узнать, как они это сделали, или, возможно, даже использовать свой код для достижения вашей цели. ссылка здесь http://esper.codehaus.org/about/nesper/nesper.html

scroll top