Reading Dustin Campbell‘s latest post reminded me that I really like Ruby’s Enumerable mixin.
One of the compelling methods in that type is each_slice (and the related enum_slice). The each/enum distinction to a C# developer can be understood as the distinction between a void method that takes a delegate, and an iterator method (a method that uses yield return) that returns an IEnumerable.
With the advent of C# 3.0 and the built-in Enumerable extension methods, returning an IEnumerable is a pretty powerful construct—developers aren’t limited to just foreach-ing over the results anymore.
So here’s a C# Slice extension method that is roughly the equivalent of Ruby’s enum_slice method:
using System; using System.Collections.Generic; namespace RubyInspiredExtensions { public static class CollectionEx { /// <summary> /// Iterates the specified sequence returning arrays of each slice of <paramref name="size"/> elements. /// The last array may contain fewer that <paramref name="size"/> elements. /// </summary> /// <typeparam name="T">The sequence element type.</typeparam> /// <param name="sequence">The source sequence.</param> /// <param name="size">The desired slice size.</param> /// <returns>A sequence of arrays containing the elements from the specified sequence.</returns> public static IEnumerable<T[]> Slice<T>(this IEnumerable<T> sequence, int size) { // validate arguments if (sequence == null) throw new ArgumentNullException("sequence"); if (size <= 0) throw new ArgumentOutOfRangeException("size"); // return lazily evaluated iterator return SliceIterator(sequence, size); } // SliceIterator: iterator implementation of Slice private static IEnumerable<T[]> SliceIterator<T>(IEnumerable<T> sequence, int size) { // prepare the result array int position = 0; T[] resultArr = new T[size]; foreach (T item in sequence) { // NOTE: performing the following test at the beginning of the loop ensures that we do not needlessly // create empty result arrays for sequences with even numbers of elements [(sequence.Count() % size) == 0] if (position == size) { // full result array; return to caller yield return resultArr; // create a new result array and reset position resultArr = new T[size]; position = 0; } // store the current element in the result array resultArr[position++] = item; } // no elements in source sequence if (position == 0) yield break; // resize partial final slice if (position < size) Array.Resize(ref resultArr, position); // return final slice yield return resultArr; } } }
[...] Filed under: C# — jacobcarpenter @ 6:39 pm So Dustin responded to my last post in the comments of his original post with the following code snippet: public static bool [...]
Pingback by Slice revisited « Jacob Carpenter’s Weblog — November 16, 2007 @ 6:39 pm
[...] Another set of extension methods Filed under: Ruby, csharp, extension methods — jacobcarpenter @ 3:16 pm In addition to the interesting diversions we’ve taken, I do want to continue presenting potentially useful code samples too. So here’s a fresh set of ruby inspired extensions: [...]
Pingback by Another set of extension methods « Jacob Carpenter’s Weblog — November 24, 2007 @ 3:30 pm