SplitUp()

namespace peSHIr.Utilities
{
 using System;
 using System.Linq;
 using System.Text;
 using System.Collections.Generic;
 
 /// <summary>Utility code for working with sequences</summary>
 public static class SequenceUtility
 {
  /// <summary>Split up sequence of items</summary>
  /// <typeparam name="T">Item type</typeparam>
  /// <param name="input">Input sequence</param>
  /// <param name="n">Maximum number of items per sublists</param>
  /// <returns>Sequence of lists with a maximum
  /// of <paramref name="n"/> items</returns>
  /// <remarks>Might need a suppression of code analysis rule
  /// CA1006 because of the nested generic type in the method
  /// signature.</remarks>
  public static IEnumerable<IEnumerable<T>>
   SplitUp<T>(this IEnumerable<T> input, int n)
  {
   // Non-lazy error checking
   if (input == null) throw new ArgumentNullException("input");
   if (n < 1) throw new ArgumentOutOfRangeException("n", n, "<1");
   return SplitUpLazy(input, n);
  }
 
  private static IEnumerable<IEnumerable<T>>
   SplitUpLazy<T>(IEnumerable<T> input, int n)
  {
   // Lazy yield based implementation
   var list = new List<T>();
   foreach (T item in input)
   {
    list.Add(item);
    if (list.Count == n)
    {
     yield return list;
     list = new List<T>();
    }
   }
   if (list.Count > 0) yield return list;
   yield break;
  }
 }
}
Example:
namespace SplitUpExample
{
  using System;
  using System.Linq;
  using System.Collections.Generic;
  using peSHIr.Utilities;
 
  class Program
  {
    static bool TraceDataCreation;
         
    static Action<string> println = text => Console.WriteLine(text);
    static Action<string> print = text => Console.Write(text);
    static Action newline = () => Console.WriteLine();
 
    static void Main(string[] args)
    {
      newline();
      println("* How can SplitUp() be used for paging");
      TraceDataCreation = false;
             
      var allData = TestData(64);
      var pagedData = allData.SplitUp(7);
      foreach (var page in pagedData)
      {
        print("Page:");
        foreach (int i in page)
        {
           print(" ");
           print(i.ToString());
        }
        newline();
      }
 
      newline();
      println("* And is it really lazy?");
      TraceDataCreation = true;
             
      println("Calling SplitUp() on infinite sequence now");
      var pagedInfinity = TestData().SplitUp(4);
 
      println("Retrieving first page now");
      var page1 = pagedInfinity.ElementAt(0);
             
      println("Retrieving third page now");
      var page3 = pagedInfinity.ElementAt(2);
             
      Action<string,int,int> results = (text,sum,count)
        => Console.WriteLine("{0}: {1}, {2}", text, sum, count);
 
      println("Showing results:");
      results("First page", page1.Sum(), page1.Count());
      results("Third page", page3.Sum(), page3.Count());
      println("So yes, SplitUp() is lazy like LINQ! ;-)");
 
#if DEBUG
      newline();
      println("(Key to quit)");
      Console.ReadKey();
#endif
    }
 
    static IEnumerable<int> TestData(int n)
    {
      return TestData().Take(n);
    }
 
    static IEnumerable<int> TestData()
    {
      // WARNING: this returns an infinite sequence!
      // Or at least: until int overflows... ;-)
      int i = 0;
      while (true)
      {
        if (TraceDataCreation)
          Console.WriteLine("Yielding {0}", i);
        yield return i++;
      }
    }
 
  }
 
}

Description

This SplitUp() extension method takes a sequence and splits it up into subsequences that each have a maximum length. See http://peshir.blogspot.nl/2011/02/example-of-c-lazy-functional.html for more information.

Details

Double click on the code to select all.

 

;