Reputation: 32112
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
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
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
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
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
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