Combinar 2 algoritmos de series temporales ordenadas

Tengo 2 series temporales que contienen objetos Bar, cada objeto Bar contiene una variable miembro de tipo long y cada serie temporal se almacena dentro de su propia BlockingCollection. La serie temporal se ordena en orden ascendente de los valores largos.

Me gusta diseñar un algoritmo de combinación que me permita eliminar la barra que contiene la variable miembro larga de valor más bajo en relación con el mismo elemento de comparación en la otra BlockingCollection.

Ejemplo, si el valor largo contenido en la primera barra (bar1) en BlockingCollection1 es más bajo que el valor largo contenido en la primera barra (bar2) en BlockingCollection2, entonces Take() from BlockingCollection1 y Add() to MasterBlockingCollection, esencialmente terminando con un flujo combinado de objetos Bar ordenados por el valor de la variable miembro larga de cada Bar.

Más tarde, me gusta extenderme a n BlockingCollections, no solo a 2. Jugué con matrices que contienen los valores largos para facilitar el mapeo, pero creo que las matrices son más útiles cuando se trabaja con punteros relacionados con este algoritmo de destino específico.

Me pregunto si alguien puede señalarme una implementación de Linq y comentar cuán costoso computacionalmente es ese enfoque. Lo pregunto porque el rendimiento es importante ya que hay cientos de millones de objetos Bar que fluyen a través de las colecciones. Si alguien tiene una idea más inteligente que usar Linq, sería muy bienvenida. Encontré algunas ideas sobre el algoritmo de fusión en DrDobbs hace algún tiempo, pero ya no puedo encontrar el artículo. En caso de que no sea evidente por ahora, me dirijo a C# (.Net4.0)

Muchas gracias

Editar: olvidé mencionar que se supone que el proceso de fusión ocurre al mismo tiempo que los trabajadores que agregan nuevos elementos a las colecciones de bloqueo (ejecutándose en diferentes tareas)

preguntado el 03 de mayo de 12 a las 15:05

Intente poner uno en una SortedList que ordene de la manera que desee, y luego AddRange de la otra lista debe ser perfecto. -

@YoryeNathan, eso sería O (n log n). Esto se puede hacer en O(n). -

@svick Solo la clasificación inicial sería O (n log n), pero ¿AddRange de SortedList no lo maneja bien en O (n)? -

¿Cómo os va a afectar el hecho de que las colecciones estén bloqueadas? ¿Podemos suponer que todas las colecciones son IsCompleted antes del comienzo de la fusión? ¿O debería esperar la fusión si algunas de las colecciones están vacías por ahora? -

@YoryeNathan: Primero, no podría hacer eso, tendría que encontrar la posición correcta para cada elemento, lo que no se puede hacer más rápido que O (log n). Segundo, SoertedList en realidad no tiene AddRange(). -

1 Respuestas

Aquí hay una implementación de Merge. Debe ejecutarse en tiempo O(cN), donde c es el número de colecciones. ¿Es esto lo que estás buscando?

    public static BlockingCollection<Bar> Merge(IEnumerable<BlockingCollection<Bar>> collections)
    {
        BlockingCollection<Bar> masterCollection = new BlockingCollection<Bar>();
        LinkedList<BarWrapper> orderedLows = new LinkedList<BarWrapper>();

        foreach (var c in collections)
            OrderedInsert(new BarWrapper { Value = c.Take(), Source = c }, orderedLows);

        while (orderedLows.Any())
        {
            BarWrapper currentLow = orderedLows.First.Value;
            orderedLows.RemoveFirst();

            BlockingCollection<Bar> collection = currentLow.Source;

            if (collection.Any())
                OrderedInsert(new BarWrapper { Value = collection.Take(), Source = collection }, orderedLows);

            masterCollection.Add(currentLow.Value);
        }
        return masterCollection;
    }

    private static void OrderedInsert(BarWrapper bar, LinkedList<BarWrapper> orderedLows)
    {
        if (!orderedLows.Any())
        {
            orderedLows.AddFirst(bar);
            return;
        }

        var iterator = orderedLows.First;
        while (iterator != null && iterator.Value.Value.LongValue < bar.Value.LongValue)
            iterator = iterator.Next;

        if (iterator == null)
            orderedLows.AddLast(bar);
        else
            orderedLows.AddBefore(iterator, bar);
    }

    class BarWrapper
    {
        public Bar Value { get; set; }
        public BlockingCollection<Bar> Source { get; set; }
    }

    class Bar
    {
        public Bar(long l)
        {
            this.LongValue = l;
        }
        public long LongValue { get; set; }
    }

contestado el 04 de mayo de 12 a las 15:05

MergeSort es un algoritmo de dos pasos para ordenar. El método anterior es efectivamente el segundo paso. Fusionar sería un mejor nombre. - Shlomo

Si cree que se puede hacer más rápido, no dude en publicar una mejor solución. No vas a ser más rápido que O(cN). - Shlomo

En cuanto a la eficiencia, podría hacer que esto sea un poco más eficiente a nivel micro, pero no lo superará sustancialmente. Aprovecha el hecho de que las colecciones secundarias que ingresan ya están ordenadas. - Shlomo

¿Hay alguna otra información que desee proporcionar? ¿Sobre cómo está funcionando la concurrencia? Añadiré la micromejora... - Shlomo

Si se fusiona en paralelo, tendrá que volver a fusionarse más tarde. - Shlomo

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.