BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

LINQ
.NET 3.5+

LINQ Style Append and Prepend Operators

Integrated Query (LINQ) includes a standard query operator to concatenate two sequences of the same type, but nothing to append or prepend a single item to a collection. However, these useful methods are simple to create.

Append and Prepend

Sometimes you will wish to add a single item to an existing sequence, either appending to the end of the collection or prepending as the new first item. LINQ includes the Concat operator, which concatenates two sequences of the same underlying type, but this does not allow the addition of just one object. You could convert the single item to a sequence with only one element and combine this with a collection. However, creating a pair of new, reusable methods for appending and prepending can make your code easier to read.

In this article we will create two such methods, naming them Append and Prepend. Each will be called in the same manner. You'll pass the sequence to be extended and the additional item. Both methods will follow the standard LINQ pattern by being extension methods that validate their parameters immediately but return the adjusted sequences using deferred execution.

To follow the examples, create a new console application project and add a class file named, "AppendPrependExtensions". This is where we'll create the extension methods.

Append Operator

Let's tackle the Append method first. The public part of the method is responsible for validating the arguments. To allow any type of collection to be appended to, we'll pass it into the method using the IEnumerable<T> interface. The new item will be of the type "T", declared as a generic type parameter. We'll check that the sequence is not null but we'll allow the single item to be null, as this is a valid case. If the sequence is valid, we'll call the AppendImpl method to perform the actual append.

The method is shown below:

public static IEnumerable<T> Append<T>(this IEnumerable<T> sequence, T toAppend)
{
    if (sequence == null) throw new ArgumentNullException("sequence");

    return AppendImpl(sequence, toAppend);
}

AppendImpl is quite simple. All we need to do is loop through the provided collection, returning each item in turn using yield return. This generates the iterator we require for deferred execution. Once the sequence is exhausted we only need to yield the appended item, which will appear last in the new sequence.

private static IEnumerable<T> AppendImpl<T>(IEnumerable<T> sequence, T toAppend)
{
    foreach (T item in sequence)
    {
        yield return item;
    }
    yield return toAppend;
}

Prepend Operator

The Prepend and PrependImpl methods are almost identical to their appending counterparts. The only difference is in the implementation method, which returns the prepended item before, rather than after, the contents of the provided sequence.

public static IEnumerable<T> Prepend<T>(this IEnumerable<T> sequence, T toPrepend)
{
    if (sequence == null) throw new ArgumentNullException("sequence");

    return PrependImpl(sequence, toPrepend);
}

private static IEnumerable<T> PrependImpl<T>(IEnumerable<T> sequence, T toPrepend)
{
    yield return toPrepend;
    foreach (T item in sequence)
    {
        yield return item;
    }
}

Testing the Methods

We can test the methods by appending and prepending items to a sequence. The code below creates an initial sequence as an integer array. It then uses the Append and Prepend methods to extend the sequence twice.

static void Main(string[] args)
{
    int[] items = new int[] { 1, 2, 3, 5, 8, 13 };

    Console.WriteLine("Append");
    Show(items.Append(21));

    Console.WriteLine("\nPrepend");
    Show(items.Prepend(1));
}

static void Show(IEnumerable<int> items)
{
    var itemStrings = items.Select(i => i.ToString());
    Console.WriteLine(itemStrings.Aggregate((a, n) => a + "," + n));
}

/* OUTPUT

Append
1,2,3,5,8,13,21

Prepend
1,1,2,3,5,8,13

*/
10 August 2013