Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extension method for Enumerable.Intersperse?

Tags:

c#

ienumerable

I learned the intersperse function from Haskell, and have been looking for an implementation in c#.

Intersperse takes 2 arguments, an IEnumerable<T> source and a T element. It returns an IEnumerable with element inserted between every element of source.

One possible use-case is to put an arbitrary integer in between a list of integers, for example:

// returns: {1, 0, 2, 0, 3}
(List<int>() {1, 2, 3}).Intersperse(0);

This is a general case of string.Join(...).

like image 870
Daniel Avatar asked Apr 15 '09 19:04

Daniel


3 Answers

Something the others have missed: if you only want it in between items, and not also in front or behind, you need to do an extra check:

public static IEnumerable<T> Intersperse<T>(this IEnumerable<T> source, T element)
{
    bool first = true;
    foreach (T value in source)
    {
        if (!first) yield return element;
        yield return value;
        first = false;
    }
}

or

public static IEnumerable<T> Intersperse<T>(this IEnumerable<T> source, T element)
{
    var e = source.GetEnumerator(); 
    bool b = e.MoveNext();
    if (b) yield return e.Current;

    while (e.MoveNext())
    {
        yield return element;
        yield return e.Current;
    }
}           
like image 121
Joel Coehoorn Avatar answered Nov 03 '22 14:11

Joel Coehoorn


I've coded up a solution that is lazy, in the spirit of Linq solutions! Other solutions I came up with involved traversing the entire list before returning data, and then returning the resulting list.

Some of the other answers have an if check on every iteration of the loop.

public static IEnumerable<T> Intersperse<T>(this IEnumerable<T> source, T element)
{
    using (var enumerator = source.GetEnumerator()) {
        if (enumerator.MoveNext()) {
            yield return enumerator.Current;
            while (enumerator.MoveNext()) {
                yield return element;
                yield return enumerator.Current;
            }
        }
    }
}
like image 27
Daniel Avatar answered Nov 03 '22 15:11

Daniel


It would be pretty easy to write:

public static IEnumerable<T> Intersperse<T>(this IEnumerable<T> source, T value) {
    bool first = true;
    foreach(T item in source) {
         if(first) { first = false; }
         else { yield return value; }
         yield return item;
    }
}
like image 2
Marc Gravell Avatar answered Nov 03 '22 15:11

Marc Gravell