JavaScript, for better or worse, has a much smaller standard library than what .NET developers are used to with the base class library (BCL). The JavaScript community has made many attempts to build a standard library, and I’m sure some of them are great. As I was scanning the options, I came across a fascinating method named intersperse, which “inserts a separator between the elements of its list argument”.

In this post, I’ll implement the same method in C# as an extension method on the IEnumerable interface.

Intersperse implementation in C#

Let’s first look at a few examples and the expected output before we look at the implementation of the method.

var hello = new string("Hello".Intersperse('-').ToArray());
var one = new string("1".Intersperse('x').ToArray());
var @null = ((IEnumerable<object>)null!).Intersperse(',').ToArray();
var array = new[] { 1, 2, 3 }.Intersperse(42).ToArray();
var menu = new [] {"Home", "About", "Privacy" }
    .Intersperse(" > ")
    .Aggregate((a, b) => $"{a}{b}");

Console.WriteLine($"'{hello}' interspersed with '-' is {hello}");
Console.WriteLine($"1 interspersed is {one}");
Console.WriteLine($"null interspersed is {@null}");
Console.WriteLine($"array interspersed is {string.Join(", ", array)}");
Console.WriteLine($"The menu is {menu}");

Running this application, we will see the following output.

'H-e-l-l-o' interspersed with '-' is H-e-l-l-o
1 interspersed is 1
null interspersed is System.Object[]
array interspersed is 1, 42, 2, 42, 3
The menu is Home > About > Privacy

Let’s get to the implementation!

public static class EnumerableExtensions
{
    public static IEnumerable<T> Intersperse<T>(
        this IEnumerable<T>? source,
        T delimiter)
    {
        if (source is null) yield break;

        using var enumerator = source.GetEnumerator();
        var hasFirstElement = enumerator.MoveNext();
        
        if (hasFirstElement == false) yield break;
        
        yield return enumerator.Current;

        while (enumerator.MoveNext())
        {
            yield return delimiter;
            yield return enumerator.Current;
        }
    }
}

I used yield to reduce the number of iterations on the collection being passed, as it would add unnecessary overhead. Additionally, I could have used a method like Zip, but that would have required more gymnastics than the current implementation.

I hope you enjoyed reading this quick blog post, and as always, thanks for reading. Cheers.