Pregunta

Estoy diseñando un marco interno simple para manejar datos de series de tiempo. Dado que LINQ es mi martillo de juguete actual, quiero golpear todo con él.

Quiero implementar métodos en la clase TimeSeries (Select (), Where (), etc.) para poder usar la sintaxis de LINQ para manejar datos de series de tiempo

Algunas cosas son sencillas, por ejemplo, (de x en A, seleccione x + 10), dando una nueva serie de tiempo.

¿Cuál es el mejor diseño de sintaxis para combinar dos o más series temporales? (de a en A de b en B, seleccione a + b) no es muy bueno, ya que expresa un bucle anidado. Tal vez algunos se unen? Esto debería corresponder a unirse en la variable de tiempo implícita. (Lo que tengo en mente corresponde a la función lisp 'zip')


EDITAR: Es necesaria alguna aclaración.

Una serie de tiempo es un tipo de función que depende del tiempo, por ejemplo, cotizaciones de bolsa. Una combinación de series de tiempo podría ser la diferencia entre dos precios de las acciones, en función del tiempo.

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

es posible, pero ¿se puede expresar claramente usando alguna sintaxis de LINQ? Espero implementar los métodos LINQ en la class MyTimeSeries a mí mismo.

¿Fue útil?

Solución

Si estoy entendiendo la pregunta correctamente, ¿quieres unir varias secuencias en función de su posición dentro de la secuencia?

No hay nada en la clase System.Linq.Enumerable para hacer esto, ya que tanto los métodos Join como GroupJoin se basan en unir teclas Sin embargo, por coincidencia escribí un método de PositionalJoin solo para este propósito hace unos días, utilizado como en su ejemplo:

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

La semántica del método que se muestra a continuación es que no requiere que las secuencias tengan la misma longitud, pero sería trivial modificarlas para requerir esto. También comenté dónde debería estar la verificación de argumentos, ya que estaba usando nuestras clases de ayuda interna.

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);
    }
}

No estoy seguro de si esto es exactamente lo que estás buscando, pero espero que te ayude.

Otros consejos

Union suena como el camino correcto, no hay soporte para expresiones de consulta, pero creo que expresa lo que quieres decir.

Es posible que le interese consultar las clases basadas en rango en MiscUtil que puede ser muy bien utilizado para los tiempos. Combinado con un poco de diversión de método de extensión, puede hacer:

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

No estoy sugiriendo que esto deba reemplazar lo que estés haciendo, solo que puedes tomar algunas ideas para hacerlo aún más ordenado. No dude en contribuir de nuevo, también :)

De mi 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);
    }
}

La sintaxis es:

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

Bjarke, eche un vistazo a NEsper, es una aplicación de procesamiento de eventos complejos de código abierto que, entre otras cosas, realiza consultas de series de tiempo similares a SQL. Puede aprender cómo lo han hecho o quizás incluso aprovechar su código para lograr su objetivo. enlace aquí http://esper.codehaus.org/about/nesper/nesper.html

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top