Task: Stream merge



C#: using System;
using System.Collections.Generic;
using System.Linq;

namespace RosettaCode
{
    static class StreamMerge
    {
        static IEnumerable<T> Merge2<T>(IEnumerable<T> source1, IEnumerable<T> source2) where T : IComparable
        {
            var q1 = new Queue<T>(source1);
            var q2 = new Queue<T>(source2);
            while (q1.Any() && q2.Any())
            {
                var c = q1.Peek().CompareTo(q2.Peek());
                if (c <= 0) yield return q1.Dequeue(); else yield return q2.Dequeue();
            }
            while (q1.Any()) yield return q1.Dequeue();
            while (q2.Any()) yield return q2.Dequeue();
        }

        static IEnumerable<T> MergeN<T>(params IEnumerable<T>[] sources) where T : IComparable
        {
            var queues = sources.Select(e => new Queue<T>(e)).Where(q => q.Any()).ToList();
            var headComparer = Comparer<Queue<T>>.Create((x, y) => x.Peek().CompareTo(y.Peek()));
            queues.Sort(headComparer);
            
            while (queues.Any())
            {
                var q = queues.First();
                queues.RemoveAt(0);
                yield return q.Dequeue();
                if (q.Any())
                {
                    var index = queues.BinarySearch(q, headComparer);
                    queues.Insert(index < 0 ? ~index : index, q);
                }
            }
        }

        static void Main()
        {
            var a = new[] { 1, 4, 7, 10 };
            var b = new[] { 2, 5, 8, 11 };
            var c = new[] { 3, 6, 9, 12 };

            foreach (var i in Merge2(a, b)) Console.Write($"{i} ");
            Console.WriteLine();

            foreach (var i in MergeN(a, b, c)) Console.Write($"{i} ");
            Console.WriteLine();
        }
    }
}








Fortran:       SUBROUTINE FILEMERGE(N,INF,OUTF)	
       INTEGER N	
       INTEGER INF(*)	
       INTEGER OUTF	
       INTEGER L(N)	
       INTEGER LIST(0:N)
       LOGICAL LIVE(N)	
       INTEGER ENUFF		
       PARAMETER (ENUFF = 666)	
       CHARACTER*(ENUFF) AREC(N)
       INTEGER I,IT	
        LIST = 0	
        LIVE = .TRUE.	
Charge the battery.
        DO I = 1,N	
          CALL GRAB(I)		
        END DO		
Chug away.
        DO WHILE(LIST(0).GT.0)	
          IT = LIST(0)		
          WRITE (OUTF,"(A)") AREC(IT)(1:L(IT))	
          LIST(0) = LIST(IT)	
          CALL GRAB(IT)		
        END DO			

       CONTAINS	
        SUBROUTINE GRAB(IN)	
         INTEGER IN		
         INTEGER IT,P		
          IF (.NOT.LIVE(IN)) RETURN	
          READ (INF(IN),1,END = 10) L(IN),AREC(IN)(1:MIN(ENUFF,L(IN)))	
    1     FORMAT (Q,A)		
Consider the place of AREC(IN) in the LIST. Entry LIST(IN) is to be linked back in.
          P = 0		
    2     IT = LIST(P)		
          IF (IT.GT.0) THEN	
            IF (AREC(IN)(1:L(IN)).GT.AREC(IT)(1:L(IT))) THEN	
              P = IT			
              GO TO 2			
            END IF		
          END IF	
          LIST(IN) = IT		
          LIST(P) = IN		
          RETURN	
   10     LIVE(IN) = .FALSE.	
          LIST(IN) = -666	
        END SUBROUTINE GRAB	
      END SUBROUTINE FILEMERGE	

      PROGRAM MASH
      INTEGER MANY
      PARAMETER (MANY = 4)	
      INTEGER FI(MANY)
      CHARACTER*(28) FNAME(MANY)
      DATA FNAME/"FileAppend.for","FileChop.for",
     1 "FileExt.for","FileHack.for"/
      INTEGER I,F

      F = 10	
      OPEN (F,FILE="Merged.txt",STATUS="REPLACE",ACTION="WRITE")	
      DO I = 1,MANY	
        FI(I) = F + I		
        OPEN (FI(I),FILE=FNAME(I),STATUS="OLD",ACTION="READ")	
      END DO		

      CALL FILEMERGE(MANY,FI,F)	

      END