Task: Range extraction



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

class RangeExtraction
{
    static void Main()
    {
        const string testString = "0,  1,  2,  4,  6,  7,  8, 11, 12, 14,15, 16, 17, 18, 19, 20, 21, 22, 23, 24,25, 27, 28, 29, 30, 31, 32, 33, 35, 36,37, 38, 39";
        var result = String.Join(",", RangesToStrings(GetRanges(testString)));
        Console.Out.WriteLine(result);
    }

    public static IEnumerable<IEnumerable<int>> GetRanges(string testString)
    {
        var numbers = testString.Split(new[] { ',' }).Select(x => Convert.ToInt32(x));
        var current = new List<int>();
        foreach (var n in numbers)
        {
            if (current.Count == 0)
            {
                current.Add(n);
            }
            else
            {
                if (current.Max() + 1 == n)
                {
                    current.Add(n);
                }
                else
                {
                    yield return current;
                    current = new List<int> { n };
                }
            }
        }
        yield return current;
    }

    public static IEnumerable<string> RangesToStrings(IEnumerable<IEnumerable<int>> ranges)
    {
        foreach (var range in ranges)
        {
            if (range.Count() == 1)
            {
                yield return range.Single().ToString();
            }
            else if (range.Count() == 2)
            {
                yield return range.Min() + "," + range.Max();
            }
            else
            {
                yield return range.Min() + "-" + range.Max();
            }
        }
    }
}








Fortran:       SUBROUTINE IRANGE(TEXT)	
Could make this a function, but then a maximum text length returned would have to be specified.
       CHARACTER*(*) TEXT	
       INTEGER LOTS		
       PARAMETER (LOTS = 666)	
       INTEGER VAL(LOTS)	
       INTEGER N		
       INTEGER I,I1		
        N = 1		
        DO I = 1,LEN(TEXT)	
          IF (TEXT(I:I).EQ.",") N = N + 1	
        END DO			
        IF (N.LE.2) RETURN	
        IF (N.GT.LOTS) STOP "Too many values
        READ (TEXT,*) VAL(1:N)	
        TEXT = ""		
        L = 0			
        I1 = 1			
   10   IF (L.GT.0) CALL EMIT(",")	
        CALL SPLOT(VAL(I1))		
        DO I = I1 + 1,N			
          IF (VAL(I - 1) + 1 .NE. VAL(I)) EXIT	
        END DO				
        IF (I - I1 .GT. 2) THEN		
          CALL EMIT("-")		
          CALL SPLOT(VAL(I - 1))	
          I1 = I			
         ELSE			
          I1 = I1 + 1			
        END IF			
        IF (I.LE.N) GO TO 10	
       CONTAINS		
        SUBROUTINE EMIT(C)	
         CHARACTER*1 C		
          L = L + 1		
          IF (L.GT.LEN(TEXT)) STOP "Ran out of text
          TEXT(L:L) = C		
        END SUBROUTINE EMIT	
        SUBROUTINE SPLOT(N)	
         INTEGER N		
         CHARACTER*12 FIELD	
         INTEGER I		
          WRITE (FIELD,"(I0)") N
          DO I = 1,12		
            IF (FIELD(I:I).LE." ") EXIT	
            CALL EMIT(FIELD(I:I))	
          END DO		
        END SUBROUTINE SPLOT	
      END	

      PROGRAM POKE
      CHARACTER*(200) SOME
      SOME = "  0,  1,  2,  4,  6,  7,  8, 11, 12, 14,  "
     1      //"  15, 16, 17, 18, 19, 20, 21, 22, 23, 24,"
     2      //"25, 27, 28, 29, 30, 31, 32, 33, 35, 36,  "
     3      //"37, 38, 39                               "
      CALL IRANGE(SOME)
      WRITE (6,*) SOME
      END