Subscribe to CurtisRutland.Write("...");        RSS Feed
-----

More extension methods: To and In. Also, a static class to make Sequences.

Icon 2 Comments
Cross-posted from my Blog.

Without further ado, here's a static class I've been working on (code after the break):

public static partial class Seq
{
    public static IEnumerable<T> Make<T>(params T[] list)
    {
        foreach (T item in list)
            yield return item;
    }

    public static IEnumerable<int> Make(int from, int to)
    {
        return Make(from, to, x => x + (from <= to ? 1 : -1));
    }

    public static IEnumerable<int> Make(int from, int by, int to)
    {
        return Make(from, to, x => x + by);
    }

    public static IEnumerable<int> Make(int from, int to, Func<int, int> by)
    {
        if (from <= to)
        {
            do
            {
                yield return from;
                from = by.Invoke(from);
            } while (from <= to);
        }
        else
        {
            do
            {
                yield return from;
                from = by.Invoke(from);
            } while (from >= to);
        }
    }

    public static IEnumerable<int> Make(int from, Func<int, int> by)
    {
        while (true)
        {
            yield return from;
            from = by.Invoke(from);
        }
    }

    public static IEnumerable<int> To(this int i, int to)
    {
        return Make(i, to);
    }

    public static IEnumerable<int> To(this int i, int to, Func<int, int> by)
    {
        return Make(i, to, by);
    }
}


This was somewhat inspired by F#'s Seq and Lists. It's not supposed to match, but I got the idea there. I also used this as an excuse to learn how to use yield return statements.

This allows you to quickly compose sequences. Right now, all but one are for Int32s. It's a known issue that there's no generic constraint for numeric types, so I can't make a generic out of these. I could theoretically make them Decimals, and just downcast using Cast<t>(), but I don't care for that. So, I made ints, and if I ever need others, I'll copy/paste with doubles/bytes/whatever. The class is partial so it can easily be extended.

Here's a few more interesting extension methods, ones that I didn't feel that were attached to this class specifically but had external use.

public static partial class Extensions
{
    public static bool In<T>(this T i, IEnumerable<T> collection)
    {
        return collection.Contains(i);
    }

    public static bool In<T>(this T i, params T[] list)
    {
        return list.Contains(i);
    }

    public static void Print<T>(this IEnumerable<T> collection, TextWriter tw = null)
    {
        if(tw == null)
            tw = Console.Out;
        tw.Write("{ ");
        int max = collection.Count();
        for (int i = 0; i < max; i++)
        {
            tw.Write(collection.ElementAt(i).ToString() + " ");
            tw.Write(i == max - 1 ? "}" : ", ");
        }
        tw.WriteLine();
    }
}


In is a simple extension method. It basically wraps and reverses the LINQ extension method Contains.

So instead of doing collection.Contains(10), we can do 10.In(collection). Kinda Ruby-ish, in my opinion. I like the syntax. It's obvious, and in some contexts, it reads better. Actually, the forum thread on another forum that started the discussion that led to these methods has an example of where this scans better:

if(25.In(18, 25)) 
  DoSomething();


Also, I've included a simple Print extension that prints any IEnumerable (though not always well), assuming that the type's ToString is defined properly.

Here's some example and test code:

class Program
{
  static void Main()
  {
	  Console.WriteLine("1.To(10)");
	  1.To(10).Print();
	  Console.WriteLine("10.To(1)");
	  10.To(1).Print();
	  Console.WriteLine("10.To(10)");
	  10.To(10).Print();
	  Console.WriteLine("1.To(10, x => x + 2)");
	  1.To(10, x => x + 2).Print();
	  Console.WriteLine("Seq.Make(0, x => x + 5).Take(10)");
	  Seq.Make(0, x => x + 5).Take(10).Print();
	  Console.WriteLine("Seq.Make(0, 100, x => x + 3)");
	  Seq.Make(0, 20, x => x + 3).Print();
	  Console.WriteLine("Seq.Make(\"abc\", \"def\", \"ghi\")");
	  Seq.Make("abc", "def", "ghi").Print();
	  Console.WriteLine("10.In(1.To(10))");
	  Console.WriteLine(10.In(1.To(10)));
	  Console.WriteLine("\"test\".In(\"test\", \"ing\")");
	  Console.WriteLine("test".In("test", "ing"));
	  Console.ReadKey();
  }
}

2 Comments On This Entry

Page 1 of 1

AdamSpeight2008 

03 November 2010 - 04:15 AM
The extension method could encompass more capabilities if they where more generic.
See vb.net example
0

Curtis Rutland 

04 November 2010 - 08:52 AM
Appreciate the advice, Adam. I'll look into it for sure.

Quick question, do you keep a library of these convenient extension methods to include in your projects, or a code file you copy over, or just add the ones you need when you need them?
0
Page 1 of 1

Trackbacks for this entry [ Trackback URL ]

There are no Trackbacks for this entry

Recent Entries

Recent Comments

1 user(s) viewing

1 Guests
0 member(s)
0 anonymous member(s)