C# 时间序列的“连接”

C# 时间序列的“连接”,c#,linq,linq-to-objects,time-series,C#,Linq,Linq To Objects,Time Series,我正在设计一个简单的内部框架来处理时间序列数据。 考虑到LINQ是我现在的玩具锤子,我想用它击打所有东西 我想在类TimeSeries Select、Where等中实现方法,以便使用LINQ语法处理时间序列数据 有些事情是直截了当的,例如,从x中选择x+10,给出一个新的时间序列 组合两个或多个时间序列的最佳语法设计是什么? 从a中的a从b中的b选择a+b并不好,因为它表示一个嵌套循环。 也许有人加入?这应该对应于隐式时间变量上的join。 我想到的是lisp的“zip”函数 编辑:一些澄清是必

我正在设计一个简单的内部框架来处理时间序列数据。 考虑到LINQ是我现在的玩具锤子,我想用它击打所有东西

我想在类TimeSeries Select、Where等中实现方法,以便使用LINQ语法处理时间序列数据

有些事情是直截了当的,例如,从x中选择x+10,给出一个新的时间序列

组合两个或多个时间序列的最佳语法设计是什么? 从a中的a从b中的b选择a+b并不好,因为它表示一个嵌套循环。 也许有人加入?这应该对应于隐式时间变量上的join。 我想到的是lisp的“zip”函数

编辑:一些澄清是必要的

时间序列是一种依赖于时间的函数,例如股票报价。 时间序列的组合可以是两个股票价格之间的差异,作为时间的函数

Stock1.MyJoin(Stock2, (a,b)=>a-b)
这是可能的,但是可以使用一些LINQ语法简洁地表达吗? 我希望自己能在MyTimeSeries类中实现LINQ方法。

Union听起来是正确的方法-不支持查询表达式,但我认为它表达了您的意思

您可能会对基于范围的类感兴趣,在这些类中可以很好地多次使用。结合一些扩展方法的乐趣,您可以:

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

我并不是说这应该取代你正在做的任何事情,只是说你可能会有一些想法让它更整洁。也请随意回复:

如果我正确理解了问题,您想根据序列中的位置加入多个序列吗

System.Linq.Enumerable类中没有任何东西可以执行此操作,因为Join和GroupJoin方法都基于连接键。然而,几天前我碰巧为此编写了一个positionJoin方法,如您的示例所示:

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);
    }
}
不确定这是否正是您想要的,但希望能有所帮助。

来自我的项目:


Bjarke,看看NEsper,它是一款开源的复杂事件处理应用程序,除了其他功能外,它还可以执行类似于SQL的时间序列查询。您可以了解他们是如何做到这一点的,或者甚至可以利用他们的代码来实现您的目标。链接这里

我真的不喜欢这个例子,因为它扩展了一个基本类型int,这不是一个好的做法。构建日期时间部分有点似是而非,但是,能够通过1.0到10构建一个范围,这使得IMO的代码非常可读。请注意,您应该将参数检查和迭代分为不同的方法-请参阅以获取详细信息。我的详细信息更复杂,因为两个时间序列可能没有完全相同的时间戳,但想法与您描述的相同。我怀疑LINQ查询语法不够用。谢谢你详细说明为什么会这样。谢谢!我会看一看,至少能得到一些灵感。
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)