Gabe Moothart
Gabe Moothart

Reputation: 32112

What is an easy way to append or prepend a single value to an IEnumerable<T>?

I need to prepend a single value to an IEnumerable (in this case, IEnumerable<string[]>). In order to do that, I'm creating a List<T> just to wrap the first value so that I can call Concat:

// get headers and data together
IEnumerable<string[]> headers = new List<string[]> {
    GetHeaders()
};
var all = headers.Concat(GetData());

Yuck. Is there a better way? And how would you handle the opposite case of appending a value?

Upvotes: 13

Views: 4684

Answers (5)

aloisdg
aloisdg

Reputation: 23531

The easiest and cleanest way for .NET 4.7.1 and newer is to use the side-effect free Prepend() and Append().

Example

// Creating an array of numbers
var numbers = new[] { 1, 2, 3 };

// Prepend and Append any value of the same type
var results = numbers.Prepend(0).Append(4);

// output is 0, 1, 2, 3, 4
Console.WriteLine(string.Join(", ", results ));

Upvotes: 0

Greg
Greg

Reputation: 23493

I wrote custom extension methods to do this:

public static IEnumerable<T> Append<T>(this IEnumerable<T> source, T item)
{
    foreach (T i in source)
        yield return i;

    yield return item;
}

public static IEnumerable<T> Prepend<T>(this IEnumerable<T> source, T item)
{
    yield return item;

    foreach (T i in source)
        yield return i;
}

In your scenario, you would write:

var all = GetData().Prepend(GetHeaders());

As chilltemp commented, this does not mutate the original collection. In true Linq fashion, it generates a new IEnumerable<T>.

Note: An eager null argument check is recommended for source, but not shown for brevity.

Upvotes: 25

Gabe Moothart
Gabe Moothart

Reputation: 32112

Another option is a helper method that creates a sequence out of a single item:

public static class EnumerableExt
{
    public static IEnumerable<T> One<T>(T item)
    {
        yield return item;
    }
}

...
//prepend:
EnumerableExt.One( GetHeaders() ).Concat( GetData() );

//append:
GetData().Concat( EnumerableExt.One( GetHeaders() );

Upvotes: 0

desco
desco

Reputation: 16782

Rx contains StartWith method that prepends value to sequence. Also Return can wrap value as sequence so it can be appended via Concat.

        var c = new[] {4};
        var c1 = c.StartWith(1, 2, 3);
        var c2 = c1.Concat(EnumerableEx.Return(5));

        c2.Run(Console.Write); // 12345

Upvotes: 1

Reed Copsey
Reed Copsey

Reputation: 564731

Use the Enumerable.Concat extension method. For appending values instead of prepending, you'd just call Concat in reverse. (ie: GetData().Concat(GetHeaders());)

If GetHeaders() returns a single string array, I'd personally probably wrap it in a single element array instead of a list:

 var all = (new[] {GetHeaders()}).Concat(GetData());

Upvotes: 8

Related Questions