internal static IEnumerable <T> MergeBy <T, TKey>(IEnumerable <IEnumerable <T> > lists, Func <T, TKey> keySelector, IComparer <TKey> comparer, bool descending)
        {
            var initialItems = lists
                               .Select(l => l.GetEnumerator())
                               .Where(i => i.MoveNext());

            IComparer <T> keyComparer = comparer != null ?
                                        new KeySelectorComparer <T, TKey>(keySelector, comparer) :
                                        new KeySelectorComparer <T, TKey>(keySelector);

            var enumerableComparer = new EnumeratorComparer <T>(keyComparer);

            DHeap <IEnumerator <T> > heap;

            if (descending)
            {
                heap = new MaxDHeap <IEnumerator <T> >(2, initialItems, enumerableComparer);
            }
            else
            {
                heap = new MinDHeap <IEnumerator <T> >(2, initialItems, enumerableComparer);
            }

            while (!heap.IsEmpty)
            {
                var i = heap.RemoveRoot();
                yield return(i.Current);

                if (i.MoveNext())
                {
                    heap.Insert(i);
                }
            }
        }
Пример #2
0
        private static IEnumerable <T> OrderedMergeHelper <T>(IEnumerable <IEnumerable <T> > sources, IComparer <T> elementComparer)
        {
            // Each sequence is expected to be ordered according to
            // the same comparison logic as elementComparer provides
            var enumerators = sources.Select(e => e.GetEnumerator());

            // Disposing sequence of lazily acquired resources as
            // a single resource
            using (var disposableEnumerators = enumerators.AsDisposable())
            {
                // The code below holds the following loop invariant:
                // - Priority queue contains enumerators that positioned at
                // sequence element
                // - The queue at the top has enumerator that positioned at
                // the smallest element of the remaining elements of all
                // sequences

                // Ensures that only non empty sequences participate  in merge
                var nonEmpty = disposableEnumerators.Where(e => e.MoveNext());
                // Current value of enumerator is its priority
                var comparer = new EnumeratorComparer <T>(elementComparer);
                // Use priority queue to get enumerator with smallest
                // priority (current value)
                var queue = new PriorityQueue <IEnumerator <T> >(nonEmpty, comparer);

                // The queue is empty when all sequences are empty
                while (queue.Count > 0)
                {
                    // Dequeue enumerator that positioned at element that
                    // is next in the merged sequence
                    var min = queue.Dequeue();
                    yield return(min.Current);

                    // Advance enumerator to next value
                    if (min.MoveNext())
                    {
                        // If it has value that can be merged into resulting
                        // sequence put it into the queue
                        queue.Enqueue(min);
                    }
                }
            }
        }