Ruby-style Array methods in C# 3.0
A while back I played with Ruby-style loops in C# 3.0. This sparked my jealousy of other fun Ruby constructs that I couldn’t find in C#, and a couple of them are the “each” and “each_with_index” methods for arrays. Here’s an example, from thinkvitamin.com:
my_vitamins = ['b-12', 'c', 'riboflavin']
my_vitamins.each do |vitamin|
puts "#{vitamin} is tasty!"
end
=> b-12 is tasty!
=> c is tasty!
=> riboflavin is tasty!
With both Arrays and List
string[] myVitamins = {"b-12", "c", "riboflavin"};Array.ForEach(myVitamins, (vitamin) => { Console.WriteLine("{0} is tasty", vitamin); } );
var myOtherVitamins = new List<string>() { “b-12”, “c”, “riboflavin” };
myOtherVitamins.ForEach( (vitamin) => { Console.WriteLine("{0} is very tasty", vitamin); } );
There are a few problems with these implementations, however:
-
Inconsistent between types
- IEnumerable
left out -
Array has a static method, whereas List
is instance - Index is unknown
, we can create a simple extension method to handle any case.
Without index
I still like the “Do” keyword in Ruby to signify the start of a block, and I’m not a fan of the readability (or “solubility”, whatever) of the “ForEach” method. Instead, I’ll borrow from the loop-style syntax I created in the previous post that uses a “Do” method:
myVitamins.Each().Do(
(vitamin) => { Console.WriteLine("{0} is tasty", vitamin); } );
To accomplish this, I’ll need something to add the “Each” method, and something to provide the “Do” method. Here’s what I came up with: <div class="CodeFormatContainer"> <pre><span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">class</span> RubyArrayExtensions -
{ public class EachIterator<T> { private readonly IEnumerable<T> values;
<span class="kwrd">internal</span> EachIterator(IEnumerable<T> values) { <span class="kwrd">this</span>.values = values; } <span class="kwrd">public</span> <span class="kwrd">void</span> Do(Action<T> action) { <span class="kwrd">foreach</span> (var item <span class="kwrd">in</span> values) { action(item); } } } <span class="kwrd">public</span> <span class="kwrd">static</span> EachIterator<T> Each<T>(<span class="kwrd">this</span> IEnumerable<T> values) { <span class="kwrd">return</span> <span class="kwrd">new</span> EachIterator<T>(values); }}
- IEnumerable
The “Each” generic method is an extension method that extends anything that implements IEnumerable<T>, which includes arrays, List<T>, and many others. IEnumerable<T> is ripe for extension, as .NET 3.5 introduced dozens of extension methods for it in the System.Linq.Enumerable class. With these changes, I now have a consistent mechanism to perform an action against an array or list of items:
<div class="CodeFormatContainer">
<pre><span class="kwrd">string</span>[] myVitamins = { <span class="str">"b-12"</span>, <span class="str">"c"</span>, <span class="str">"riboflavin"</span> };
myVitamins.Each().Do( (vitamin) => { Console.WriteLine("{0} is tasty", vitamin); } );
var myOtherVitamins = new List<string>() { “b-12”, “c”, “riboflavin” };
myOtherVitamins.Each().Do( (vitamin) => { Console.WriteLine("{0} is very tasty", vitamin); } );
### With index
Ruby also has a “each\_with\_index” method for arrays, and in this case, there aren’t any existing methods on System.Array or List<T> to accomplish this. With extension methods, this is still trivial to accomplish. I now just include the index whenever executing the callback to the Action<T, int> passed in. Here’s the extension method with the index:
<div class="CodeFormatContainer">
<pre><span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">class</span> RubyArrayExtensions
{ public class EachWithIndexIterator<T> { private readonly IEnumerable<T> values;
<span class="kwrd">internal</span> EachWithIndexIterator(IEnumerable<T> values)
{
<span class="kwrd">this</span>.values = values;
}
<span class="kwrd">public</span> <span class="kwrd">void</span> Do(Action<T, <span class="kwrd">int</span>> action)
{
<span class="kwrd">int</span> i = 0;
<span class="kwrd">foreach</span> (var item <span class="kwrd">in</span> values)
{
action(item, i++);
}
}
}
<span class="kwrd">public</span> <span class="kwrd">static</span> EachWithIndexIterator<T> EachWithIndex<T>(<span class="kwrd">this</span> IEnumerable<T> values)
{
<span class="kwrd">return</span> <span class="kwrd">new</span> EachWithIndexIterator<T>(values);
}
}
The only difference here is I keep track of an index to send back to the delegate passed in from the client side, which now looks like this:
<div class="CodeFormatContainer">
<pre><span class="kwrd">string</span>[] myVitamins = { <span class="str">"b-12"</span>, <span class="str">"c"</span>, <span class="str">"riboflavin"</span> };
myVitamins.EachWithIndex().Do( (vitamin, index) => { Console.WriteLine("{0} cheers for {1}!", index, vitamin); } );
var myOtherVitamins = new List<string>() { “b-12”, “c”, “riboflavin” };
myOtherVitamins.EachWithIndex().Do( (vitamin, index) => { Console.WriteLine("{0} cheers for {1}!", index, vitamin); } );
