June 2009 Archives

Inclusively Take Elements using LINQ and Custom Extensions

2 Comments

I ran into an interesting LINQ problem recently, one which required me to extend LINQ in my own fashion. The problem was fairly simple. I’m trying to build a list of every day a course meets over the course of a term. I start by querying our Academic Calendar for every event in the calendar, then I skip all the events prior to the first day of class, taking all the events until the end of classes for the term. I couldn’t just take those two events, because different events in the middle of the term affect if courses are offered. My first draft at this problem was simple:

IEnumerable<AcademicEvent> _events = GetAcademicCalendarEvents
                            (data.Year, data.Term, data.Campus)
                .SkipWhile(c => c.EventType != "TermBegins")
                .TakeWhile(c => c.EventKey != "TermEnds");

This code is broken. But the error is subtle. The TakeWhile method is not inclusive. The resulting IEnumerable will not include the event with the Key “TermEnds”, resulting in my later code inadvertently not showing some days at the end of the term. Given that the event that follows the TermEnds event may not always be the same, I didn’t really want to try to key off of the next possible event. What I really wanted to do was take items on the list until I reached the TermEnds event. Sounds like an easy enough extension method!

public static IEnumerable<T> TakeUntil<T>
    (this IEnumerable<T> data, Func<T, bool> predicate)
{
    return data.TakeWhile(c => !predicate(c));
}

And since the messing around with the IEnumerable has already been done for me, I might as well take advantage of that work, and just reverse the predicate as I send it into the existing TakeWhile. Of course, this doesn’t work either. Because TakeWhile (and by extension, TakeUntil) will not return the item which triggered the predicate, which I want. So, another extension method is required, TakeUntilInclusive.

public static IEnumerable<T> TakeUntilInclusive
        (this IEnumerable<T> data, Func<T, bool> predicate)
{
    int index = 0;
    var enumerator = data.GetEnumerator();
    while (enumerator.MoveNext())
    {
        index++;
        if (predicate(enumerator.Current)) { break; }
    }
    enumerator.Dispose();
    return data.Take(index);
}

And while I’m at it…

public static IEnumerable<T> TakeWhileInclusive<T>
    (this IEnumerable<T> data, Func<T, bool> predicate)
{
    return data.TakeUntilInclusive(p => !predicate(p));
}

I’ve mentioned extension methods before, but I can honestly say that they are the single best reason for using C# 3, and .NET 3/3.5. They’re that good. Essentially, extension methods bring limited monkey-patching to the static compilation world, but do so in a really selective way. All the code above would be wrapped in a static class in a Namespace that would allow me to select when those methods were available or not. The only weakness to extension methods is that they do not allow you to override methods that already exist with new behavior. Really, it’s just a compiler hack, which is why it’s a language feature and not a runtime feature, but it’s a really good compiler hack.

Breaking down the syntax is easy. Any static method, located in a static class, with a first argument prefixed with the ‘this’ keyword, will be interpreted by the compiler as an extension method, and the compiler will allow the method to be called as object.Method(), instead of StaticClass.Method(object). Essentially, those two calls are functionally identical, but the extension method provides code that is cleaner and easier to read. However, it’s real power is when paired with interfaces and generics, as with LINQ, which my code above just adds on to.

The final version of the query looks like this:

IEnumerable<AcademicEvent> _events = GetAcademicCalendarEvents
                        (data.Year, data.Term, data.Campus)
                .SkipWhile(c => c.EventType != "TermBegins")
                .TakeUntilInclusive(c => c.EventKey == "TermEnds");

For clarity, I could create a SkipUntil wrapper around SkipWhile, but given that SkipWhile is doing what I want anyway, I didn’t feel it was necessary. Now, this code works against an IEnumerable, not an IQueryable, so it can really only be used on data sets small enough to be handled in memory. I’m not entirely sure how I’d implement this in an IQueryable, as that object expects to be able to translate to SQL (or similar) at some point, and this isn’t the sort of thing that I can think of how to do in a single query.

Writing Extension methods is really easy, and LINQ is the best example of their power so far. The fact that you can so easily extend upon this existing work is fantastic, and I can think of a few other problems I’m liable to have to solve in the coming months where I’ll be using these extension methods, or some new ones.

Sub-$20 Apartment-Friendly Clothesline

My wife loves the smell of air-dried clothing. Personally, I don’t particularly care, but I also don’t have any direct love of machine-dried clothing either (except for the feeling of fresh-from-the-drier pants). However, we live in an Apartment, second floor, and while there is a lot of grass around our apartment (one of the many benefits of campus housing), the University had no interest in putting up a clothesline, particularly since my wife was probably the only person in our complex asking for it. However, our apartment does have a small deck area, and Landlord-Tenant Law always has provisions for tenants making improvements to the property their renting.

So, we had a small deck, covered from above by the deck of our upstairs neighbors. The design, therefore, was simple. Four eye-hooks and some cord is really all you need, but we found a ~$10 USD cinch that, while being half the cost of the project, was completely worth it. At the time I completed this project, I didn’t have a power drill, only a Dremel, but for my needs that was plenty.

Tools: * Drill or Rotary Tool * Socket Wrench * Sharp Knife/Scissors * 4 Circular Hooks * Clothesline or Rope * Clothesline Cinch (optional)

When deciding on Hooks and line, consider how big your space is, and how many clothes you think you’ll be able to hang. For us, we went with hardware that would be able to support ~50 lbs. This was seriously overkill for our purposes, as our deck was really small, but if we move, we plan to take this hardware with us, and to be honest, finding line that’s much weaker that that is kind of hard. Consider the ratings of what you’re buying, and how much you plan to hang up. At least with the ~50 lbs limit on our line, we can air-dry sweaters and stuff in the fall before it gets too cold. Clothesline - DoubleHitch Knot

Installation was simple. Drill very shallow holes for the circular hooks. These need to be big enough around for you to start the hooks into the wood, but the holes are mostly to keep the hardware going in the wall straight. Find a socket that fits the circular hook, and attach that to your socket wrench, and use that to drive the hooks all the way in. The socket wrench will provide you with the leverage you need to drive the hooks all the way in, and will save your hands from trying to turn them directly. Once all four hooks are in place, choose a corner to tie the line down to, and tie it down using a simple knot. I’d suggest either a bowline, or a double hitch.

Once tied down, just run the line through your hooks, until you reach the other side. If not using the cinch, cut to length and tie down reasonably hard using the same sort of knot as on the other side. You don’t want to pull so hard that your hooks (or line) fails, but the line should be as taut as possible. If using the cinch, simply attach the cinch with a short piece of line from the eye hook on the wall, then string the line from the opposite side through the cinch and pull it tight.Clothesline - Cinch Hardware

So, why air dry? Well, the California Energy Comission claims that a dryer is typically the second largest energy user in your household, second only the the Refrigerator. That site estimates the operating costs of a clothes dryer at around $85 per year, or $1500 over 18 years of operation. It adds up over time, no doubt. Plus, some clothing items shouldn’t be machine-dried, and the clothesline is exactly what these items require.

I’m not advocating completely forsaking the machine dryer. We certainly don’t have room for enough line to make that even possible, and nearly half the year, the weather simply isn’t compatible with the idea of the clothesline. But, it does save some energy, provides clothing a fresh clean smell you can’t get any other way, and it’s an inexpensive thing to do. That $20 price tag I put on this project includes the clothespins.