Wilsonhut

Deal with it or don't

Monthly Archives: November 2012

Obvious Extension Method: TakeAllButLast

I had a previous post about TakeAllButLast, but here’s a more succinct version which also has a callback for the untaken records.

Basically, Linq provides us with the extension method Take(x) to get the first x items in an enumerable. It also gives us Skip(x) to take all but the first x items. There is no “TakeAllButLast(x)” or “SkipLast(x)” equivalent.

public static class EnumerableExtensions
{
    public static IEnumerable<T> TakeAllButLast<T>(this IEnumerable<T> items, int count, Action<T> onUntaken = null)
    {
        if (items == null)
            throw new ArgumentNullException("items");

        if (count < 0)
            throw new ArgumentOutOfRangeException("count");

        var buffer = new Queue<T>(count + 1);

        foreach (var item in items)
        {
            buffer.Enqueue(item);

            if (buffer.Count == count + 1)
            {
                yield return buffer.Dequeue();
            }
        }
        if (onUntaken != null)
        {
            foreach (var x in buffer)
            {
                onUntaken(x);
            }
        }
    }
}

 

You’d use this like this example where you’re processing a file that has ONE Trailer record:

using (var reader = new StreamReader(_inputFile))
{
    var fileLines = reader.GetLines().TakeAllButLast(1);
}

…which also uses my GetLines method for a TextReader.

And now, with the callback, you can take a peek at the last line that it skipped:

using (var reader = new StreamReader(_inputFile))
{
    string lastLine;
    var fileLines = reader.GetLines().TakeAllButLast(1, line => lastLine = line);
}

Obvious Extension Method: TextReader GetLines()

I don’t know about you, but looping through a TextReader or StreamReader looks ugly to me. I’d rather have the lines of the file returned as an IEnumerable<string>

So here it is. Easy Schpeasy.

 

  1.     public static class TextReaderExtensions
  2.     {
  3.         public static IEnumerable<string> GetLines(this TextReader streamReader)
  4.         {
  5.             string fileLine;
  6.             while ((fileLine = streamReader.ReadLine()) != null)
  7.             {
  8.                 yield return fileLine;
  9.             }
  10.         }
  11.     }

Now the code using it looks like this:

  1.             using (var reader = new StreamReader("someFile.txt"))
  2.             {
  3.                 foreach (var fileLine in reader.GetLines())
  4.                 {
  5.                     //pretty!
  6.                 }
  7.             }

…and you can use all your favorite Linq on there!