Skip to content

Instantly share code, notes, and snippets.

@dwcullop
Last active August 29, 2015 14:23
Show Gist options
  • Save dwcullop/e042ab8904681691cb7d to your computer and use it in GitHub Desktop.
Save dwcullop/e042ab8904681691cb7d to your computer and use it in GitHub Desktop.
Class that implements extension methods for Interleaving multiple collections into one collection.(e.g. [A, A, A,] + [B, B, B] = [A, B, A, B, A, B])
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
namespace DareWare.Utils.Extensions
{
/// <summary>
/// Interleave (v.): To intersperse (something) at regular intervals between parts of a thing
/// Source: http://en.wiktionary.org/wiki/interleave#Verb
/// </summary>
static public class CollectionInterleave
{
#region Main Worker Methods
/// <summary>
/// Takes a collection of enumerables and returns a single enumerable with the contents of the inputs
/// interleaved together. If the input enumerables are [1, 1, 1] and [2, 2, 2, 2, 2] then the output will be
/// [1, 2, 1, 2, 1, 2, 2, 2].
/// </summary>
/// <typeparam name="T">The datatype of the collection contents</typeparam>
/// <param name="enumerables">The collection of collections to be interwoven</param>
/// <returns>A collection with the contents of all of the source collections interleaved together</returns>
/// <exception cref="System.ArgumentNullException">Thrown if all of the input IEnumerables are NULL</exception>
static public IEnumerable<T> Interleave<T>( IEnumerable<IEnumerable<T>> enumerables )
{
// Get an enumerator for each non-null enumerable
var enumerators = enumerables.Where( w => (w != null) )
.Select( s => s.GetEnumerator() )
.ToList();
try
{
var active = enumerators.AsEnumerable();
// Reduce the collection down to the ones where MoveNext is true
while ( (active = active.Where( w => w.MoveNext() ).ToArray()).Any() )
{
// For each of those, return one value each
foreach ( var c in active )
{
yield return c.Current;
}
}
}
finally
{
// When all done, dispose each enumerator
foreach ( var d in enumerators )
{
d.Dispose();
}
}
}
#endregion Main Worker Methods
#region Extension Methods
/// <inheritdoc />
/// <remarks>
/// Syntactic sugar to make the above overload more fun to call. Enables syntax such as:
/// <c>coll1.Interleave( coll2, coll3 );</c> which interleaves the three collections together.
/// </remarks>
/// <param name="first">The first collection to be interleaved</param>
/// <param name="others">Array of other collections to be interleaved</param>
static public IEnumerable<T> Interleave<T>( this IEnumerable<T> first, params IEnumerable<T>[] others )
{
if ( first == null )
{
throw new ArgumentNullException( "first", "The 'this' parameter cannot be NULL" );
}
return Interleave<T>( Enumerable.Repeat( first, 1 ).Concat( others ) );
}
#endregion Extension Methods
}
}
@dwcullop
Copy link
Author

I needed this today so I whipped it up. Now it turns out I don't need it... 😬 So I'm sharing to make sure that time wasn't wasted and at least someone can benefit from it. If this helps you, let me know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment