I found this post looking for the same thing, but was very unhappy with the answers (most seem to be about joining strings [?], and the accepted answer seems verbose). So I ended up just figuring out some other ways to do it.
The way I prefer is this:
public static IEnumerable<T> AfterEach <T> (this IEnumerable<T> source, T delimiter) =>
source.SelectMany((item) => Enumerable.Empty<T>().Append(item).Append(delimiter));
Or, alternatively:
public static IEnumerable<T> AfterEach <T> (this IEnumerable<T> source, T delimiter) =>
source.SelectMany((item) => new T[] { item, delimiter });
They're both equivalent: For each item, create a new sequence { item, delimiter }, and use SelectMany
to concatenate those all together.
Another approach, which isn't a one liner but might be easier to read and is very straightforward:
public static IEnumerable<T> AfterEach <T> (this IEnumerable<T> source, T delimiter) {
foreach (T item in source) {
yield return item;
yield return delimiter;
}
}
If you don't want the extra delimiter on the end, the approach is similar, except you concatenate { delimiter, item } sequences then Skip
the extra delimiter at the beginning (this is more performant than skipping one at the end).
public static IEnumerable<T> Delimit <T> (this IEnumerable<T> source, T delimiter) =>
source.SelectMany((item) => Enumerable.Empty<T>().Append(delimiter).Append(item)).Skip(1);
public static IEnumerable<T> Delimit <T> (this IEnumerable<T> source, T delimiter) =>
source.SelectMany((item) => new T[] { delimiter, item }).Skip(1);
The yield approach would be like this (again, two similar options, just depends on how you're feeling):
public static IEnumerable<T> Delimit <T> (this IEnumerable<T> source, T delimiter) {
foreach (T item in source.Take(1)) // protects agains empty source
yield return item;
foreach (T item in source.Skip(1)) {
yield return delimiter;
yield return item;
}
}
public static IEnumerable<T> Delimit <T> (this IEnumerable<T> source, T delimiter) {
static IEnumerable<U> Helper<U> (IEnumerable<U> source, U delimiter) {
foreach (U item in source) {
yield return delimiter;
yield return item;
}
}
return Helper(source, delimiter).Skip(1);
}
There's some runnable examples and test code (for Delimit
, not AfterEach
) here. There's an implementation with Aggregate
there too that I didn't think was worth writing about here. It could be adapted to AfterEach
in a similar manner.