Jacob Carpenter’s Weblog

November 16, 2007

Ruby inspired extension method

Filed under: csharp, extension methods, Ruby — Jacob @ 12:00 am

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;
        }
    }
}

Advertisements

2 Comments »

  1. […] 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

  2. […] 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


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: