29

If I have two sequences and I want to process them both together, I can union them and away we go.

Now lets say I have a single item I want to process between the two sequencs. I can get it in by creating an array with a single item, but is there a neater way? i.e.

var top = new string[] { "Crusty bread", "Mayonnaise" };
string filling = "BTL";
var bottom = new string[] { "Mayonnaise", "Crusty bread" };

// Will not compile, filling is a string, therefore is not Enumerable
//var sandwich = top.Union(filling).Union(bottom);

// Compiles and works, but feels grungy (looks like it might be smelly)
var sandwich = top.Union(new string[]{filling}).Union(bottom);

foreach (var item in sandwich)
    Process(item);

Is there an approved way of doing this, or is this the approved way?

Thanks

Binary Worrier
  • 50,774
  • 20
  • 136
  • 184
  • 1
    This is how I tend to do it.. doesn't feel happy but never figured it was worth working around.. Wonder if there's a way to write an implicit conversion between T and T array.. – Jimmy Hoffa Aug 20 '10 at 15:15
  • possible duplicate of [Favorite way to create an new IEnumerable sequence from a single value?](http://stackoverflow.com/questions/1019737/favorite-way-to-create-an-new-ienumerablet-sequence-from-a-single-value) – nawfal Feb 17 '13 at 12:32
  • 1
    You can simplify the union expression just a tad by reducing new string[] to just new[]. Otherwise, Jon Hanna's solution is probably the best way to go about this if you end up doing this sort of thing often. – Alex Jorgenson Nov 14 '14 at 19:18

4 Answers4

37

One option is to overload it yourself:

public static IEnumerable<T> Union<T>(this IEnumerable<T> source, T item)
{
    return source.Union(Enumerable.Repeat(item, 1));
}

That's what we did with Concat in MoreLINQ.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    Enumerable.Repeat, perfect, thanks. I might indeed use that overload, thanks. – Binary Worrier Aug 20 '10 at 15:12
  • 1
    For extra nerdiness, name the overload `cons` :D – Marc Bollinger Aug 20 '10 at 15:13
  • 2
    Every so often, when writing C# code, I do find myself longing for the set operation operators from languages like F# or LISP. Syntax like `list :: item` or `list1 @ list2` tend to be quite readable, once you're used to them. – LBushkin Aug 20 '10 at 15:49
12

The new way of doing this, supported in .NET Core and .NET Framework from version 4.7.1, is using the Append extension method.

This will make your code as easy and elegant as

var sandwich = top.Append(filling).Union(bottom);
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
7

Consider using even more flexible approach:

public static IEnumerable<T> Union<T>(this IEnumerable<T> source, params T[] items)
{
    return source.Union((IEnumerable<T>)items);
}

Works for single as well as multiple items. You may also accept null source values:

public static IEnumerable<T> Union<T>(this IEnumerable<T> source, params T[] items)
{
    return source != null ? source.Union((IEnumerable<T>)items) : items;
}
Kędrzu
  • 2,385
  • 13
  • 22
5

I tend to have the following somewhere in my code:

public static IEnumerable<T> EmitFromEnum<T>(this T item)
{
  yield return item;
}

While it's not as neat to call col.Union(obj.EmitFromEnum()); as col.Union(obj) it does mean that this single extension method covers all other cases I might want such a single-item enumeration.

Update: With .NET Core you can now use .Append() or .Prepend() to add a single element to an enumerable. The implementation is optimised to avoid generating too many IEnumerator implementations behind the scenes.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251