代码之家  ›  专栏  ›  技术社区  ›  Bjarke Ebert

时间序列的“连接”

  •  3
  • Bjarke Ebert  · 技术社区  · 16 年前

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

    我想在类时间序列中实现方法(select(),where()等等),以便使用LINQ语法处理时间序列数据

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

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


    编辑: 需要澄清。

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

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

    是可能的,但是可以使用一些LINQ语法整齐地表示出来吗? 我希望在 class MyTimeSeries 我自己。

    4 回复  |  直到 15 年前
        1
  •  0
  •   Greg Beech    16 年前

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

    里面什么都没有 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);
        }
    }
    

    不确定这是否正是你想要的,但希望能有所帮助。

        2
  •  1
  •   Jon Skeet    16 年前

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

    您可能会对中基于范围的类感兴趣 MiscUtil 它可以很好地用于时间。再加上一点扩展方法的乐趣,您可以做到:

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

    我不是建议你用这个来代替你正在做的任何事情,只是为了让你的想法更整洁。你也可以自由地做出贡献:)

        3
  •  1
  •   Cameron MacFarland    16 年前

    从我 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)
    
        4
  •  1
  •   endian    16 年前

    Bjarke,看看Nesper,它是一个开源的复杂事件处理应用程序,除此之外,它还执行类似SQL的时间序列查询。您可以了解他们是如何做到这一点的,或者甚至可以利用他们的代码来实现您的目标。链接在这里 http://esper.codehaus.org/about/nesper/nesper.html